From bf5116f1650f15d13e82cd0f3d5f9406099dcd81 Mon Sep 17 00:00:00 2001 From: Laifsyn <99366187+Laifsyn@users.noreply.github.com> Date: Thu, 20 Jun 2024 08:41:27 -0500 Subject: [PATCH] (lab 1-3) Pilas, Recursividad & Colas- Estructura de Datos (#11) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Laboratorio de Pilas * Implementar los Eventos basicos de la aplicacion * Implementar Impresion como Pila de la pila * Terminar de dibujar una interfaz sencilla para el laboratorio. * Laboratorio 1 * Labortorio 2 - Recursividad * update main.rs * Usar BigInt para el calculo de Factorial Adicionalmente usar colores para mensaes de error * Usar Tailcall Implementar versión con tailcall para evitar stackoverflow en entradas relativamente grandes * fx typo * fix parsing step * remove uneeded code * test commit * file restructuring * Implementar Cola y su Abstract * Tidy up blank spaces * stage changes - App + Visual Output * Stage Changes * stage changes * Laboratorio 3 - Colas simples y circulares --- .vscode/settings.json | 5 +- eclipse-formatter.xml | 4 +- .../com/utp/clsEstructuraDatos/.gitignore | 2 + .../com/utp/clsEstructuraDatos/Cargo.toml | 19 ++ .../clsEstructuraDatos/Estructuras/Pila.java | 231 ++++++++++++++ .../Estructuras/colas/AbstractCola.java | 284 ++++++++++++++++++ .../Estructuras/colas/ColaCircular.java | 32 ++ .../Estructuras/colas/ColaSimple.java | 56 ++++ .../laboratorio_1/Main.java | 201 +++++++++++++ .../laboratorio_2_rust/main.rs | 210 +++++++++++++ .../laboratorio_3/Main.java | 260 ++++++++++++++++ .../com/utp/clsEstructuraDatos/rustfmt.toml | 47 +++ .../pry3/DrawTable.java | 2 +- 13 files changed, 1349 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/utp/clsEstructuraDatos/.gitignore create mode 100644 src/main/java/com/utp/clsEstructuraDatos/Cargo.toml create mode 100644 src/main/java/com/utp/clsEstructuraDatos/Estructuras/Pila.java create mode 100644 src/main/java/com/utp/clsEstructuraDatos/Estructuras/colas/AbstractCola.java create mode 100644 src/main/java/com/utp/clsEstructuraDatos/Estructuras/colas/ColaCircular.java create mode 100644 src/main/java/com/utp/clsEstructuraDatos/Estructuras/colas/ColaSimple.java create mode 100644 src/main/java/com/utp/clsEstructuraDatos/laboratorio_1/Main.java create mode 100644 src/main/java/com/utp/clsEstructuraDatos/laboratorio_2_rust/main.rs create mode 100644 src/main/java/com/utp/clsEstructuraDatos/laboratorio_3/Main.java create mode 100644 src/main/java/com/utp/clsEstructuraDatos/rustfmt.toml diff --git a/.vscode/settings.json b/.vscode/settings.json index a4e4aba..3092ab3 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,7 @@ { "java.format.settings.url": "eclipse-formatter.xml", - "java.checkstyle.configuration": "${workspaceFolder}\\checkstyle.xml" + "editor.tokenColorCustomizations": { + "comments": "", + "textMateRules": [] + } } \ No newline at end of file diff --git a/eclipse-formatter.xml b/eclipse-formatter.xml index 7f8c57d..6806aea 100644 --- a/eclipse-formatter.xml +++ b/eclipse-formatter.xml @@ -114,10 +114,10 @@ - + - + diff --git a/src/main/java/com/utp/clsEstructuraDatos/.gitignore b/src/main/java/com/utp/clsEstructuraDatos/.gitignore new file mode 100644 index 0000000..2ebc5ea --- /dev/null +++ b/src/main/java/com/utp/clsEstructuraDatos/.gitignore @@ -0,0 +1,2 @@ +/target +/Cargo.lock \ No newline at end of file diff --git a/src/main/java/com/utp/clsEstructuraDatos/Cargo.toml b/src/main/java/com/utp/clsEstructuraDatos/Cargo.toml new file mode 100644 index 0000000..5803888 --- /dev/null +++ b/src/main/java/com/utp/clsEstructuraDatos/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "clsEstructuraDatos" +version = "0.1.0" +edition = "2021" + + +[[bin]] +name = "laboratorio_2" +path = "laboratorio_2_rust/main.rs" + + +[dependencies] +colored = "2.1.0" +inquire = "0.7.5" +num-bigint = "0.4.5" +tailcall = "1.0.1" + +[features] +tailcall = [] diff --git a/src/main/java/com/utp/clsEstructuraDatos/Estructuras/Pila.java b/src/main/java/com/utp/clsEstructuraDatos/Estructuras/Pila.java new file mode 100644 index 0000000..86d1163 --- /dev/null +++ b/src/main/java/com/utp/clsEstructuraDatos/Estructuras/Pila.java @@ -0,0 +1,231 @@ +package com.utp.clsEstructuraDatos.Estructuras; + +import java.util.ArrayList; + +public class Pila { + public static void main(String[] args) { + Pila pila = new Pila<>(10); + pila.insertar(10); + pila.insertar(10); + pila.insertar(1); + pila.insertar(-415); + pila.insertar(1104); + pila.insertar(110); + pila.insertar(141); + pila.insertar(4142); + pila.insertar(11242); + pila.insertar(1414214); + System.out.println("Cima: " + pila.getCima()); + System.out.println(pila.imprimirPila()); + pila.quitarCima(); + System.out.println("Quitar cima"); + System.out.println(pila.imprimirPila()); + pila.insertar(6); + System.out.println("Insertar 6"); + System.out.println(pila.imprimirPila()); + // pila.limpiarPila(); + // System.out.println("Limpiar pila"); + // System.out.println(pila.imprimirPila()); + } + + private int cima = 0; + private final int capacidad; + private ArrayList inner; + + public Pila(int capacidad) { + this.capacidad = capacidad; + this.inner = new ArrayList<>(capacidad); + } + + public boolean insertar(T dato) { + if (this.cima == this.capacidad) { + return false; + } + + // Nunca limpiamos el arreglo, asi que al insertar tenemos que reemplazar el + // indice si existe + if (this.cima < this.inner.size()) { + this.inner.set(this.cima, dato); + } else { + this.inner.add(dato); + } + this.cima++; + return true; + } + + public void limpiarPila() { + this.cima = 0; + } + + public T quitarCima() { + if (this.cima == 0) { + return null; + } + this.cima--; + return this.inner.remove(this.cima); + } + + public T verCima() { + if (this.cima == 0) { + return null; + } + return this.inner.get(this.cima - 1); + } + + public boolean pilaVacia() { + return this.cima == 0; + } + + public boolean pilaLLena() { + return this.cima == this.capacidad; + } + + // public String impresion_sencilla() { + // StringBuilder sb = new StringBuilder(); + // Integer index_width = 0; + // int cima = this.cima; + // while (cima > 0) { + // cima /= 10; + // index_width++; + // } + // String encabezado_indice = "Indice"; + // String encabezado_valores = "Valores"; + + // if (encabezado_indice.length() > index_width) { + // index_width = encabezado_indice.length(); + // } + // int cell_width = encabezado_valores.length(); + // for (T cell : this.inner) { + // int cell_length = cell.toString().length(); + // if (cell_length > cell_width) { + // cell_width = cell_length; + // } + // } + + // String encabezado = String.format("| %" + index_width + "s | %" + cell_width + // + "s |\n", encabezado_indice, + // encabezado_valores); + // sb.append(encabezado); + // sb.append(String.format("├%" + (encabezado.length() - 3) + "s┤\n", + // "").replace(" ", "─")); + // for (int i = 1; i <= this.cima; i++) { + // String cell = this.inner.get(i - 1).toString(); + // sb.append(String.format("| %" + index_width + "s | ", i)); + // sb.append(String.format("%" + cell_width + "s |", cell)); + // sb.append("\n"); + // } + // return sb.toString(); + // } + + public String imprimirPila() { + // Imprimimos de cima a base de la pila. + DrawTable tabla = new DrawTable(); + + for (int indice = this.cima; indice > 0; indice--) { + tabla.insertar_fila(new String[] { String.valueOf(indice), this.inner.get(indice - 1).toString() }); + } + + tabla.insertar_fila(new String[] { "Indice", "Valores" }); + return tabla.toString(); + } + + public int getCima() { + return this.cima; + } + + public int getCapacidad() { + return this.capacidad; + } + +} + +class DrawTable { + private int cantidad_columnas = 0; + private ArrayList table; + + public DrawTable() { + this.table = new ArrayList<>(); + } + + public void insertar_fila(String[] row) { + if (this.cantidad_columnas == 0) { + this.cantidad_columnas = row.length; + } + // Todas las filas tienen que tener la misma cantidad columna + if (this.cantidad_columnas != row.length) { + throw new IllegalArgumentException("La fila no tiene la misma cantidad de columnas que las anteriores"); + } + this.table.add(row); + } + + public String toString() { + StringBuilder sb = new StringBuilder(); + // Guardo la posicion de los vertices de la tabla. + Integer[] columns_widths = new Integer[this.cantidad_columnas]; + + // Obtener los vertices de la tabla + for (int indice_columna = 0; indice_columna < this.cantidad_columnas; indice_columna++) { + int ancho_columna = 0; + for (String[] fila : this.table) { + String celda = fila[indice_columna]; + if (celda.length() >= ancho_columna) { + // +1 para el caracter que encierra la celda + ancho_columna = celda.length() + 1; + columns_widths[indice_columna] = ancho_columna; + } + } + } + + StringBuilder borde_superior = new StringBuilder("┌"); + StringBuilder separador_fila = new StringBuilder("├"); + StringBuilder borde_inferior = new StringBuilder("└"); + // Construimos los separadores + for (int indice_columna = 0; indice_columna < this.cantidad_columnas; indice_columna++) { + int padding = columns_widths[indice_columna]; + // El ultimo caracter se encierra con algo distinto. + + borde_superior.append(String.format("%" + padding + "s", "┬").replace(" ", "─")); + separador_fila.append(String.format("%" + padding + "s", "┼").replace(" ", "─")); + borde_inferior.append(String.format("%" + padding + "s", "┴").replace(" ", "─")); + if (indice_columna == this.cantidad_columnas - 1) { + borde_superior.setLength(borde_superior.length() - 1); + separador_fila.setLength(separador_fila.length() - 1); + borde_inferior.setLength(borde_inferior.length() - 1); + } + } + borde_superior.append("┐\n"); + separador_fila.append("┤\n"); + borde_inferior.append("┘\n"); + + sb.append(borde_superior); + char barra_vertical = '│'; + // Usamos Vanilla For para poder insertar separador de fila despues del + // encabezado + for (int indice_fila = 0; indice_fila < this.table.size(); indice_fila++) { + sb.append(barra_vertical); + for (int indice_columna = 0; indice_columna < this.cantidad_columnas; indice_columna++) { + String celda = this.table.get(indice_fila)[indice_columna]; + int padding = columns_widths[indice_columna]; + sb.append(String.format("%" + padding + "s", celda + barra_vertical)); + } + sb.append("\n"); + if (indice_fila == this.table.size() - 2) { + sb.append(separador_fila); + } + } + sb.append(borde_inferior); + return sb.toString(); + } + + public static void main(String[] args) { + + String[][] mi_tabla = new String[][] { { "Hola mundo", "asdfa", "Nostradamus" }, + { "1", "23jgadsdsavghgh", "3" }, + { "4", "5", "6" } }; + DrawTable table = new DrawTable(); + for (String[] fila : mi_tabla) + table.insertar_fila(fila); + System.out.println(table.toString()); + System.exit(0); + } +} diff --git a/src/main/java/com/utp/clsEstructuraDatos/Estructuras/colas/AbstractCola.java b/src/main/java/com/utp/clsEstructuraDatos/Estructuras/colas/AbstractCola.java new file mode 100644 index 0000000..a809f2d --- /dev/null +++ b/src/main/java/com/utp/clsEstructuraDatos/Estructuras/colas/AbstractCola.java @@ -0,0 +1,284 @@ +package com.utp.clsEstructuraDatos.Estructuras.colas; + +import java.awt.Color; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; + +import javax.swing.JLabel; +import javax.swing.JPanel; + +public abstract class AbstractCola { + /** + * Indice donde se puede extraer el siguiente elemento + */ + int frente = 0; + /** + * Indice donde se puede insertar el siguiente elemento + */ + int cola = 0; + /** + * Cantidad de elementos en la cola + */ + int longitud = 0; + /** + * Capacidad máxima de la cola + */ + int capacidad; + /** + * Arreglo que contiene los elementos de la cola + */ + final T[] inner; + + @SuppressWarnings("unchecked") + public AbstractCola(int capacidad) { + this.capacidad = capacidad; + this.inner = (T[]) new Object[capacidad]; + } + + public int capacity() { + return this.capacidad; + } + + /** + * Evalua si la cola está vacía al comparar la longitud con 0 + */ + public boolean isEmpty() { + return this.longitud == 0; + } + + /** + * Evalua si la cola está llena al comparar la longitud con la capacidad + */ + public boolean isFull() { + return this.longitud == this.capacidad; + } + + /** + * Limpia la cola y la deja vacía, y reinicia la cola. + */ + public Result.ColaVacia limpiar() { + for (int i = 0; i < capacidad; i++) { + this.inner[i] = null; + } + this.reset(); + return new Result.ColaVacia(capacidad); + } + + /** + * Reinicia los indices de frente y cola, y la longitud de la cola + */ + public void reset() { + this.frente = 0; + this.cola = 0; + this.longitud = 0; + } + + /** Cantidad de elementos accesibles en la cola */ + public int len() { + return this.longitud; + } + + /** + * Devuelve una representación opinionada de la cola en forma de cadena + */ + public String toString() { + StringBuilder sb = new StringBuilder("["); + for (int i = 0; i < capacidad; i++) { + T elemento = inner[i]; + if (elemento == null) + sb.append("_"); + else + sb.append(elemento); + sb.append(", "); + } + + // Remueve la última coma + sb.delete(sb.length() - 2, sb.length()); + sb.append("]"); + return sb.toString(); + } + + public PanelDrawer as_drawer() { + return new PanelDrawer(this); + } + + public class PanelDrawer { + final AbstractCola cola; + final JLabel front_surplus = new JLabel(); + final JLabel frente_item = new JLabel(); + final JLabel middle = new JLabel(); + final JLabel cola_item = new JLabel(); + final JLabel cola_surplus = new JLabel(); + + /** + * ?["{frente-1}"] + * ["{this[frente]}"] + * [..."{longitud}"...] + * ["...{this[cola-1]}] + * ?[cola-1 - capacidad] + */ + PanelDrawer(AbstractCola cola) { + this.cola = cola; + } + + public int frente() { + return this.cola.frente; + } + + public int cola() { + return this.cola.cola; + } + + public int longitud() { + return this.cola.longitud; + } + + public int capacity() { + return this.cola.capacity(); + } + + public JPanel as_panel() { + JPanel panel = new JPanel(new GridBagLayout()); + var c = new GridBagConstraints(); + c.insets = new Insets(2, 5, 5, 5); + c.fill = GridBagConstraints.HORIZONTAL; + c.gridx = 0; + c.gridy = 0; + + panel.add(front_surplus, c); + c.gridy = 1; + panel.add(frente_item, c); + c.gridy = 2; + panel.add(middle, c); + c.gridy = 3; + panel.add(cola_item, c); + c.gridy = 4; + panel.add(cola_surplus, c); + + int frente = this.cola.frente; + int cola = this.cola.cola; + + // ****************************************** + + if (frente > cola) + wrapped(); + else + aligned(); + + // ****************************************** + return panel; + } + + /** + * llamado cuando frente (donde se retira de la fila) es menor o igual que el + * indice de la cola + */ + public void aligned() { + int frente = this.frente(); + if (frente > 0) { + this.front_surplus.setText("[+" + (frente) + "...]"); + this.front_surplus.setForeground(Color.BLACK); + this.front_surplus.setToolTipText("Espacio libre antes del frente"); + } else { + this.front_surplus.setText(""); + this.front_surplus.setToolTipText(null); + } + update_content(); + + int capacidad = this.capacity(); + if (this.longitud() < capacidad) { + this.cola_surplus.setText("[...+" + (capacidad - this.cola()) + "]"); + this.cola_surplus.setForeground(Color.BLACK); + this.cola_surplus.setToolTipText("Espacio libre para inserción"); + } else { + this.cola_surplus.setText("[Full]"); + this.cola_surplus.setForeground(Color.RED); + this.cola_surplus.setToolTipText(null); + } + } + + /** + * llamado cuando frente (donde se retira de la fila) es mayor que el indice de + * la cola + */ + public void wrapped() { + int frente = this.frente(); + this.front_surplus.setText("Frente idx: (" + frente + ")"); + this.front_surplus.setToolTipText("Indice de frente"); + update_content(); + + if (this.longitud() < this.capacity()) { + this.cola_surplus.setText("[...+" + (frente - this.cola()) + "]"); + this.cola_surplus.setForeground(Color.BLACK); + this.cola_surplus.setToolTipText("Espacio libre para inserción"); + } else { + this.cola_surplus.setText("[Full]"); + this.cola_surplus.setForeground(Color.RED); + this.cola_surplus.setToolTipText(null); + } + } + + void update_content() { + + // ****************************************** + + if (longitud > 0) { + this.frente_item.setText("Frente: [" + this.cola.inner[frente] + "]"); + this.frente_item.setForeground(Color.BLACK); + this.frente_item.setToolTipText("Elemento en la posición de frente"); + } else { + this.frente_item.setText("Frente: [_EMPTY_]"); + this.frente_item.setForeground(Color.RED); + this.frente_item.setToolTipText("La cola está vacía"); + } + // ****************************************** + + if (longitud > 0) { + this.middle.setText("Longitud: [..." + longitud + "...]"); + this.middle.setForeground(Color.BLACK); + this.middle.setToolTipText("Cantidad de elementos en la cola"); + } else { + this.middle.setText("Longitud: [0]"); + this.middle.setForeground(Color.RED); + this.middle.setToolTipText("No hay elementos en la cola"); + } + + // ****************************************** + int cola_index_item = (this.cola() - 1) % capacidad; + if (cola_index_item < 0) { + cola_index_item += capacidad; + } + if (longitud > 0) { + this.cola_item.setText("Cola: [" + this.cola.inner[cola_index_item] + "]"); + this.cola_item.setForeground(Color.BLACK); + this.cola_item.setToolTipText("Elemento en la posición de cola"); + } else { + this.cola_item.setText("Cola: [_EMPTY_]"); + this.cola_item.setForeground(Color.RED); + this.cola_item.setToolTipText("La cola está vacía"); + } + + // ****************************************** + } + + } + +// @formatter:off + abstract public Result insertar(T elemento); + abstract public Option quitar(); + + public static sealed interface Result { + public record OK() implements Result {} + public record ColaLlena() implements Result {} + public record ColaVacia(int size_hint) implements Result {} +// @formatter:on + } + +// @formatter:off + public static sealed interface Option { + public record Some(T value) implements Option {} + public record None() implements Option {} + } +// @formatter:on +} diff --git a/src/main/java/com/utp/clsEstructuraDatos/Estructuras/colas/ColaCircular.java b/src/main/java/com/utp/clsEstructuraDatos/Estructuras/colas/ColaCircular.java new file mode 100644 index 0000000..ed7a126 --- /dev/null +++ b/src/main/java/com/utp/clsEstructuraDatos/Estructuras/colas/ColaCircular.java @@ -0,0 +1,32 @@ +package com.utp.clsEstructuraDatos.Estructuras.colas; + +public class ColaCircular extends AbstractCola { + public ColaCircular(int capacidad) { + super(capacidad); + } + + @Override + public Result insertar(T elemento) { + if (this.isFull()) + return new Result.ColaLlena(); + + this.inner[cola] = elemento; + + this.cola = (cola + 1) % capacidad; + this.longitud++; + return new Result.OK(); + } + + @Override + public Option quitar() { + if (this.isEmpty()) + return new Option.None<>(); + + T elemento = this.inner[frente]; + inner[frente] = null; + + frente = (frente + 1) % capacidad; + longitud--; + return new Option.Some<>(elemento); + } +} diff --git a/src/main/java/com/utp/clsEstructuraDatos/Estructuras/colas/ColaSimple.java b/src/main/java/com/utp/clsEstructuraDatos/Estructuras/colas/ColaSimple.java new file mode 100644 index 0000000..63f0314 --- /dev/null +++ b/src/main/java/com/utp/clsEstructuraDatos/Estructuras/colas/ColaSimple.java @@ -0,0 +1,56 @@ +package com.utp.clsEstructuraDatos.Estructuras.colas; + +public class ColaSimple extends AbstractCola { + /** + *

+ * Una `ColaSimple` difiere de una circular, en que la longitud (lo que + * indica si + * la cola está vacía o llena) no se reinicia hasta que no hayan elementos en la + * cola. + *

+ * + *

+ * Esto quiere decir que antes de que se reinicie la longitud, lo más que se + * puede insertar o quitar son `ColaSimple.capacidad` elementos + *

+ * + * @param capacidad + * int + */ + public ColaSimple(int capacidad) { + super(capacidad); + } + + /** + * Inserta un elemento en la cola. + * Condicion de llenado: Cuando la longitud de la cola es igual a la capacidad. + */ + @Override + public Result insertar(T elemento) { + if (this.isFull()) + return new Result.ColaLlena(); + + this.inner[cola] = elemento; + + this.cola = (cola + 1) % capacidad; + this.longitud++; + return new Result.OK(); + } + + /** + * Quita un elemento de la cola, si la cola está vacía retorna una cola vacía. + */ + @Override + public Option quitar() { + if (this.isEmpty()) + return new Option.None<>(); + + T elemento = this.inner[frente]; + this.inner[frente] = null; + frente = (frente + 1) % capacidad; + if (frente == cola) + this.reset(); + return new Option.Some(elemento); + } + +} \ No newline at end of file diff --git a/src/main/java/com/utp/clsEstructuraDatos/laboratorio_1/Main.java b/src/main/java/com/utp/clsEstructuraDatos/laboratorio_1/Main.java new file mode 100644 index 0000000..81d3959 --- /dev/null +++ b/src/main/java/com/utp/clsEstructuraDatos/laboratorio_1/Main.java @@ -0,0 +1,201 @@ +package com.utp.clsEstructuraDatos.laboratorio_1; + +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JOptionPane; + +import java.awt.Font; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.TextArea; +import java.util.ArrayList; + +import com.utp.clsEstructuraDatos.Estructuras.Pila; +public class Main { + public static void main(String[] args) { + App app = new App(); + app.start(); + } +} + +class App { + ArrayList botones = new ArrayList<>(); + final String laboratorio_1 = "Laboratorio 1"; + Pila pila; + + TextArea textArea = new TextArea(); + + void start() { + JFrame frame = new JFrame(laboratorio_1); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setSize(800, 600); + frame.setLayout(new GridBagLayout()); + add_button_commands(frame); + GridBagConstraints c = new GridBagConstraints(); + + // Representación en vivo de la Pila + c.gridy = 2; + c.gridwidth = 8; + this.textArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 14)); + this.textArea.setEditable(false); + frame.add(this.textArea, c); + + frame.setVisible(true); + } + + JButton create_stack = new JButton("Crear Pila"); + JButton push = new JButton("Insertar"); + JButton pop = new JButton("Quitar"); + JButton is_empty = new JButton("Pila vacia?"); + JButton is_full = new JButton("Pila llena?"); + JButton clear = new JButton("Limpiar Pila"); + JButton peek = new JButton("Ver Cima"); + JButton display = new JButton("Imprimir Pila"); + + void add_button_commands(JFrame frame) { + // Deshabilitar botones que solo pueden ser llamados con una pila instanciada. + this.push.setEnabled(false); + this.pop.setEnabled(false); + this.is_empty.setEnabled(false); + this.is_full.setEnabled(false); + this.clear.setEnabled(false); + this.peek.setEnabled(false); + this.display.setEnabled(false); + + this.create_stack.addActionListener(e -> { + String input = JOptionPane.showInputDialog("Ingrese el tamaño de la pila"); + if (input == null || input.isEmpty()) { + error_dialogue("Entrada vacía"); + return; + } + try { + int value = Integer.parseInt(input); + event_manager(new Command.CreateStack(value)); + } catch (Exception ex) { + error_dialogue(String.format("`%s` no puede ser convertido a entero", input)); + } + }); + this.push.addActionListener(e -> { + String input = JOptionPane.showInputDialog("Ingrese el valor a insertar"); + if (input == null || input.isEmpty()) { + error_dialogue("Entrada vacía"); + return; + } + try { + int value = Integer.parseInt(input); + event_manager(new Command.Push(value)); + } catch (Exception ex) { + error_dialogue(String.format("`%s` no puede ser convertido a entero", input)); + } + }); + this.pop.addActionListener(e -> event_manager(new Command.Pop())); + this.is_empty.addActionListener(e -> event_manager(new Command.isEmpty())); + this.is_full.addActionListener(e -> event_manager(new Command.isFull())); + this.clear.addActionListener(e -> event_manager(new Command.Clear())); + this.peek.addActionListener(e -> event_manager(new Command.Peek())); + this.display.addActionListener(e -> event_manager(new Command.DisplayStack())); + + frame.add(this.create_stack); + frame.add(this.push); + frame.add(this.pop); + frame.add(this.is_empty); + frame.add(this.is_full); + frame.add(this.clear); + frame.add(this.peek); + frame.add(this.display); + + return; + } + + void event_manager(Command cmd) { + switch (cmd) { + case Command.CreateStack cs -> { + if (this.pila != null) { + // Confirmar deshacer la pila actual + int option = JOptionPane.showConfirmDialog(null, "Desea reemplazar la pila actual?", laboratorio_1, + JOptionPane.YES_NO_OPTION); + if (option == JOptionPane.NO_OPTION) + return; + } + this.pila = new Pila(cs.value()); + + this.create_stack.setText("Reemplazar Pila"); + // habilitar botones que solo pueden ser llamados con una pila instanciada. + this.push.setEnabled(true); + this.pop.setEnabled(true); + this.is_empty.setEnabled(true); + this.is_full.setEnabled(true); + this.clear.setEnabled(true); + this.peek.setEnabled(true); + this.display.setEnabled(true); + + JOptionPane.showMessageDialog(null, + String.format("Se creo una pila de capacidad para %d enteros", cs.value()), + laboratorio_1, JOptionPane.INFORMATION_MESSAGE); + } + case Command.Push(Integer value) -> { + if (this.pila.insertar(value)) + JOptionPane.showMessageDialog(null, String.format("Se inserto el valor %d", value), laboratorio_1, + JOptionPane.INFORMATION_MESSAGE); + else + error_dialogue("La pila esta llena"); + } + case Command.Pop() -> { + if (this.pila.pilaVacia()) { + error_dialogue("La pila esta vacia"); + return; + } + JOptionPane.showMessageDialog(null, String.format("Se elimino el valor %d", this.pila.quitarCima()), + laboratorio_1, JOptionPane.INFORMATION_MESSAGE); + } + case Command.isEmpty() -> { + final String msg = (this.pila.pilaVacia() ? "La pila esta vacia" : "La pila no esta vacia") + + String.format(". Tiene %d elementos", this.pila.getCima()); + JOptionPane.showMessageDialog(null, msg, laboratorio_1, JOptionPane.INFORMATION_MESSAGE); + } + case Command.isFull() -> { + final String msg = (this.pila.pilaLLena() ? "La pila esta llena" : "La pila no esta llena") + + String.format(". Le quedan %d espacios", this.pila.getCapacidad() - this.pila.getCima()); + JOptionPane.showMessageDialog(null, msg, laboratorio_1, JOptionPane.INFORMATION_MESSAGE); + } + case Command.Clear() -> { + this.pila.limpiarPila(); + JOptionPane.showMessageDialog(null, "Se limpio la pila", laboratorio_1, + JOptionPane.INFORMATION_MESSAGE); + } + case Command.Peek() -> { + if (this.pila.pilaVacia()) { + error_dialogue("La pila esta vacia"); + return; + } + JOptionPane.showMessageDialog(null, String.format("El valor en la cima es %d", this.pila.verCima()), + laboratorio_1, JOptionPane.INFORMATION_MESSAGE); + } + case Command.DisplayStack() -> { + TextArea textArea = new TextArea(this.pila.imprimirPila()); + textArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 14)); + textArea.setEditable(false); + JOptionPane.showMessageDialog(null, textArea, laboratorio_1, + JOptionPane.INFORMATION_MESSAGE); + } + } + this.textArea.setText(this.pila.imprimirPila()); + } + + void error_dialogue(String msg) { + JOptionPane.showMessageDialog(null, msg, laboratorio_1, JOptionPane.ERROR_MESSAGE); + } +} + +// @formatter:off +sealed interface Command { + public record CreateStack(int value) implements Command {} + public record Push(Integer value) implements Command {} + public record Pop() implements Command {} + public record isEmpty() implements Command {} + public record isFull() implements Command {} + public record Clear() implements Command {} + public record Peek() implements Command {} + public record DisplayStack() implements Command{} +} +// @formatter:on \ No newline at end of file diff --git a/src/main/java/com/utp/clsEstructuraDatos/laboratorio_2_rust/main.rs b/src/main/java/com/utp/clsEstructuraDatos/laboratorio_2_rust/main.rs new file mode 100644 index 0000000..08b0ad2 --- /dev/null +++ b/src/main/java/com/utp/clsEstructuraDatos/laboratorio_2_rust/main.rs @@ -0,0 +1,210 @@ +#![allow(non_snake_case)] +#![allow(unused_imports)] +#![allow(clippy::needless_return)] + +use colored::Colorize; +use inquire::{Confirm, InquireError, Select, Text}; +fn main() { + let fibonaccies: [u128; 20] = [ + 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, + ]; + for i in 1..=45 { + let num = fib(i).expect("No es fibonacci de 0"); + println!("Fib({i}) = {num}"); + assert_eq!(fibonaccies[i as usize - 1], num) + } + + for i in 1..20 { + let num = factorial(i); + println!("factorial({i}) = {}", num.unwrap()); + } + + let _ = dbg!(Q(2, 3)); + let _ = dbg!(Q(14, 3)); + let _ = dbg!(Q(5861, 7)); + spawn_app(); +} + +fn spawn_app() { + use inquire::InquireError::*; + let funciones = vec!["Fibonacci", "Factorial", "Q", "L"]; + 'app: loop { + let ans = loop { + break match Select::new("Elija una función", funciones.clone()) + .with_help_message("↑↓ para mover, {Enter} para seleccionar, escriba para filtrar") + .prompt() { + Ok(ans) => ans, + Err(error) => { + println!("Error: {error}"); + if matches!(error, OperationCanceled | OperationInterrupted) { + break 'app; + } + continue; + } + }; + }; + + // Obtener la función seleccionada para luego compararlo en el `switch` + let funcion = Funcs::from_str(ans).unwrap(); // El selector solo tiene funciones válidad cargadas + // Obtener los argumentos para la función + let args = loop { + break match leer_argumentos(funcion) { + Ok(args) => args, + Err(error) => { + println!("Error: {error}", error = error.to_string().bright_red().bold()); + if matches!(error, OperationCanceled | OperationInterrupted) { + break 'app; + } + continue; + } + }; + }; + + // Ejecutar la función seleccionada + #[rustfmt::skip] + match funcion { + Funcs::Q => {println!("Q({}, {}) = {}", args[0], args[1], Q(args[0], args[1]))}, + Funcs::L => {println!("L({}) = {}", args[0], L(args[0]))}, + Funcs::Fibonacci => { + let Some(fibonacci) = fib(args[0]) else { + println!("{}", format!("Fibonacci({}) no es calculable", args[0]).bright_red().bold()); + continue; + }; + println!("Fibonacci({}) = {fibonacci}", args[0]) + }, + Funcs::Factorial => { + let Some(factorial) = factorial(args[0]) else { + println!("{}", format!("Factorial({}) no es calculable", args[0]).bright_red().bold()); + continue; + }; + println!("Factorial({}) = {factorial} \n{}", args[0], format!("({} digitos)", factorial.to_string().len()).on_black().cyan()); + }, + }; + match Confirm::new("Desea salir?").with_placeholder("Y/N").prompt() { + Ok(true) | Err(OperationInterrupted) => break, + _=>(), + } + } + println!("Adios!"); +} + +fn leer_argumentos(funcion: Funcs) -> Result, InquireError> { + let help_message = match funcion { + Funcs::Q => "Ejemplo: 25, 2", + _ => "Ejemplo: 24" + }; + let ans = Text::new(&format!("Ingrese los argumentos de {funcion}.")) + .with_help_message(help_message) + .prompt()? + .split(',') + .map(|arg| arg.trim().parse::()) + .collect::, _>>() + .map_err(|e| InquireError::Custom(format!("Error: {e}").into()))?; + use Funcs::*; + let argumentos_requeridos = match funcion { + Fibonacci => 1, + Factorial => 1, + Q => 2, + L => 1, + }; + (ans.len() >= argumentos_requeridos).then_some(()).ok_or(InquireError::Custom( + format!( + "La función {funcion:?} requiere `{argumentos_requeridos}` argumento(s), pero se \ + escribieron `{}` argumento(s)", + ans.len() + ) + .into(), + ))?; + Ok(ans) +} + +#[derive(Debug, Copy, Clone)] +enum Funcs { + Fibonacci, + Factorial, + Q, + L, +} +impl Funcs { + fn from_str(s: &str) -> Option { + match s { + "Fibonacci" => Some(Self::Fibonacci), + "Factorial" => Some(Self::Factorial), + "Q" => Some(Self::Q), + "L" => Some(Self::L), + _ => None, + } + } +} +impl std::fmt::Display for Funcs { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Funcs::Fibonacci => write!(f, "Fibonacci(n)"), + Funcs::Factorial => write!(f, "Factorial(n)"), + Funcs::Q => write!(f, "Q(n,b)"), + Funcs::L => write!(f, "L(n)"), + } + } +} + +fn fib(nth: usize) -> Option { + match nth { + 0 => return None, // Fibonacci de 0 no es calculable + 1 => return Some(0), + 2 => return Some(1), + _ => (), + } + + let mut left: u128 = 0; + let mut right: u128 = 1; + let mut result: u128 = 0; + + // Iterar desde 3 hasta nth inclusive + for _ in 3..=nth { + result = left.checked_add(right)?; + left = right; + right = result; + } + return Some(result); +} + +/// Factorial Recursivo +#[cfg(not(feature = "tailcall"))] +fn factorial(n: usize) -> Option { + if let 0..=1 = n { + return Some(1.into()); + } else { + return num_bigint::BigInt::from(n).checked_mul(&factorial(n - 1)?); + } +} + +/// Factorial Recursivo +/// Compilar con `tailcall` para usar esta función +/// `cargo run --release --features "tailcall"` +#[cfg(feature = "tailcall")] +fn factorial>(n: T) -> Option { + use num_bigint::BigUint; + let n = n.try_into().ok()?; + #[tailcall::tailcall] + fn tail_recursive_factorial(n: u16, acc: BigUint) -> BigUint { + match n { + 0 => acc, + _ => tail_recursive_factorial(n - 1, acc * n) + } + } + return Some(tail_recursive_factorial(n, 1u8.into())); +} + +fn Q(a: usize, b: usize) -> usize { + if a < b { + return 0; + } + return Q(a - b, b) + 1; +} + +fn L(n: usize) -> usize { + if n == 1 { + return 0; + } + return L(n / 2) + 1; +} diff --git a/src/main/java/com/utp/clsEstructuraDatos/laboratorio_3/Main.java b/src/main/java/com/utp/clsEstructuraDatos/laboratorio_3/Main.java new file mode 100644 index 0000000..c683b38 --- /dev/null +++ b/src/main/java/com/utp/clsEstructuraDatos/laboratorio_3/Main.java @@ -0,0 +1,260 @@ +package com.utp.clsEstructuraDatos.laboratorio_3; + +import javax.management.RuntimeErrorException; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JOptionPane; +import javax.swing.JPanel; + +import com.utp.clsEstructuraDatos.Estructuras.colas.AbstractCola; +import com.utp.clsEstructuraDatos.Estructuras.colas.ColaCircular; +import com.utp.clsEstructuraDatos.Estructuras.colas.ColaSimple; + +import static com.utp.clsEstructuraDatos.laboratorio_3.ColasApp.CMD.*; + +import java.awt.Dimension; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; + +public class Main { + public static void main(String[] args) { + ColasApp app = new ColasApp(); + app.run_app(); + } +} + +class ColasApp { + static public String LABORATORIO = "Laboratorio 3"; + final JButton btn_crear_cola = new JButton("Crear Cola"); + final JButton btn_insertar = new JButton("Insertar"); + final JButton btn_quitar = new JButton("Quitar"); + final JButton btn_limpiar = new JButton("Limpiar"); + final JButton btn_mostrar = new JButton("Mostrar"); + final JPanel display_area = new JPanel(); + final JFrame frame = new JFrame(LABORATORIO); + AbstractCola.PanelDrawer drawer; + AbstractCola cola; + + static int COLA_CIRCULAR = 0; + static int COLA_SIMPLE = 1; + + public void run_app() { + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setSize(800, 600); + frame.add(content()); + frame.setVisible(true); + frame.pack(); + var pref_size = frame.getPreferredSize(); + int pref_width = Math.max(pref_size.width, 275); + frame.setSize(pref_width, pref_size.height); + this.send_command(null); + } + + ColasApp() { + this.btn_crear_cola.addActionListener(e -> { + + String input = JOptionPane.showInputDialog(frame, "Ingrese la capacidad de la cola", "Crear Cola", + JOptionPane.QUESTION_MESSAGE); + try { + Integer.parseInt(input); + } catch (NumberFormatException e1) { + JOptionPane.showMessageDialog(frame, "Debe ingresar un número entero", + "Error", + JOptionPane.ERROR_MESSAGE); + return; + } + int capacidad_cola = Integer.parseInt(input); + this.send_command(new CrearCola(capacidad_cola)); + }); + this.btn_insertar.addActionListener(e -> { + String input = JOptionPane.showInputDialog(frame, "Ingrese el elemento a insertar", "Insertar", + JOptionPane.QUESTION_MESSAGE); + try { + Integer.parseInt(input); + } catch (NumberFormatException e1) { + JOptionPane.showMessageDialog(frame, "Debe ingresar un número entero", "Error", + JOptionPane.ERROR_MESSAGE); + return; + } + int elemento = Integer.parseInt(input); + this.send_command(new Insertar<>(elemento)); + }); + this.btn_quitar.addActionListener(e -> { + this.send_command(new Quitar()); + }); + this.btn_limpiar.addActionListener(e -> { + this.send_command(new Limpiar()); + }); + this.btn_mostrar.addActionListener(e -> { + this.send_command(new Mostrar()); + }); + } + + JPanel content() { + JPanel content = new JPanel(); + content.setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.fill = GridBagConstraints.BOTH; + c.insets.set(2, 3, 2, 3); + c.gridx = 0; + c.gridy = 0; + content.add(buttons_panel(), c); + + c.gridy = 1; + content.add(display_area, c); + return content; + } + + JPanel buttons_panel() { + JPanel buttons_panel = new JPanel(); + buttons_panel.setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.fill = GridBagConstraints.BOTH; + c.insets.set(2, 3, 2, 3); + + c.gridwidth = 2; + buttons_panel.add(this.btn_crear_cola, c); + + c.gridy = 1; + c.gridwidth = 1; + buttons_panel.add(this.btn_insertar, c); + c.gridx = 1; + buttons_panel.add(this.btn_quitar, c); + + c.gridy = 2; + c.gridx = 0; + buttons_panel.add(this.btn_limpiar, c); + c.gridx = 1; + buttons_panel.add(this.btn_mostrar, c); + + c.gridy = 3; + c.gridx = 0; + + return buttons_panel; + } + + // Packs the frame to the preferred size, updating if undersized + public void try_pack() { + Dimension current_size = frame.getSize(); + Dimension preferred_size = frame.getPreferredSize(); + int new_width = Math.max(current_size.width, preferred_size.width); + int new_height = Math.max(current_size.height, preferred_size.height); + if (new_width != current_size.width || new_height != current_size.height) + frame.setSize(new_width, new_height); + } + + public int prompt_colas_type() { + int num = JOptionPane.showOptionDialog(frame, "Seleccione el tipo de cola a utilizar", + LABORATORIO + ": Tipo de Cola", + JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE, null, + new String[] { "Cola Circular", "Cola Simple" }, "Cola Circular"); + return num; + } + + void switch_buttons(boolean value) { + this.btn_insertar.setEnabled(value); + this.btn_quitar.setEnabled(value); + this.btn_limpiar.setEnabled(value); + this.btn_mostrar.setEnabled(value); + } + + // Event Manager + public void send_command(CMD command) { + switch (command) { + case Pack() -> { + this.try_pack(); + } + case Redraw() -> { + if (this.cola == null) + return; + else if (this.drawer.cola() < this.drawer.frente() || (this.drawer.longitud() == this.drawer.capacity() + && this.drawer.cola() <= this.drawer.frente())) + this.drawer.wrapped(); + else + this.drawer.aligned(); + this.try_pack(); + } + case CrearCola(int capacidad_cola) -> { + int cola = prompt_colas_type(); + if (this.cola != null) { + this.cola.limpiar(); + this.drawer.aligned(); + } + if (cola == COLA_CIRCULAR) { + this.cola = new ColaCircular<>(capacidad_cola); + } else { + this.cola = new ColaSimple<>(capacidad_cola); + } + String new_text = String.format("[%s (c:%d)]Recrear Cola", this.cola.getClass().getSimpleName(), + this.cola.capacity()); + this.btn_crear_cola.setText(new_text); + switch_buttons(true); + this.drawer = this.cola.as_drawer(); + this.display_area.removeAll(); + this.display_area.add(drawer.as_panel()); + drawer.aligned(); + this.send_command(new Redraw()); + this.try_pack(); + } + case Insertar(Integer elemento) -> { + this.cola.insertar(elemento); + this.send_command(new Redraw()); + } + case Quitar() -> { + this.cola.quitar(); + this.send_command(new Redraw()); + } + case Limpiar() -> { + this.cola.limpiar(); + this.send_command(new Redraw()); + } + case Mostrar() -> { + JOptionPane.showMessageDialog(frame, this.cola.toString(), "Cola", JOptionPane.INFORMATION_MESSAGE); + } + case null -> { + } + default -> { + throw new RuntimeErrorException(null, "Unsopported Command " + command.getClass().getName()); + } + } + if (this.cola == null) { + this.btn_crear_cola.setText("Crear Cola"); + switch_buttons(false); + } else { // Only operations that can be done on a non-null queue + if (this.cola.len() <= 0) { + this.btn_quitar.setEnabled(false); + this.btn_quitar.setToolTipText("No hay elementos para quitar"); + this.btn_limpiar.setEnabled(false); + this.btn_limpiar.setToolTipText("No hay elementos para limpiar"); + } else { + this.btn_quitar.setEnabled(true); + this.btn_quitar.setToolTipText(null); + this.btn_limpiar.setEnabled(true); + this.btn_limpiar.setToolTipText(null); + } + + if (this.cola.len() == this.cola.capacity()) { + this.btn_insertar.setEnabled(false); + this.btn_insertar.setToolTipText("La cola está llena"); + } else { + this.btn_insertar.setEnabled(true); + this.btn_insertar.setToolTipText(null); + } + } + } + + public static sealed interface CMD { + // @formatter:off + /** + * Agranda la ventana al tamaño preferido, actualizando si está subdimensionada. + */ + public static record Pack() implements CMD {} + public static record CrearCola(int capacidad_cola) implements CMD {} + public static record Insertar(T elemento) implements CMD {} + public static record Quitar() implements CMD {} + public static record Limpiar() implements CMD {} + public static record Mostrar() implements CMD {} + public static record Redraw() implements CMD {} + // @formatter:on + } +} diff --git a/src/main/java/com/utp/clsEstructuraDatos/rustfmt.toml b/src/main/java/com/utp/clsEstructuraDatos/rustfmt.toml new file mode 100644 index 0000000..93502b7 --- /dev/null +++ b/src/main/java/com/utp/clsEstructuraDatos/rustfmt.toml @@ -0,0 +1,47 @@ +# Update to nightly for nightly gated rustfmt fields +# Command: "rustup toolchain install nightly" + +# Add to setting.json of your profile in VSCode +# "rust-analyzer.rustfmt.extraArgs": [ +# "+nightly" +# ], +######################################## + +# I can't rely on contributors using .editorconfig +newline_style = "Unix" +# require the shorthand instead of it being optional +use_field_init_shorthand = true +# outdated default — `?` was unstable at the time +# additionally the `try!` macro is deprecated now +use_try_shorthand = false +# Max to use the 100 char width for everything or Default. See https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#use_small_heuristics +use_small_heuristics = "Max" +# Unstable features below +unstable_features = true +version = "Two" +# code can be 100 characters, why not comments? +comment_width = 100 +# force contributors to follow the formatting requirement +error_on_line_overflow = true +# error_on_unformatted = true ## Error if unable to get comments or string literals within max_width, or they are left with trailing whitespaces. +# next 4: why not? +format_code_in_doc_comments = true +format_macro_bodies = true ## Format the bodies of macros. +format_macro_matchers = true ## Format the metavariable matching patterns in macros. +## Wraps string when it overflows max_width +format_strings = true +# better grepping +imports_granularity = "Module" +# quicker manual lookup +group_imports = "StdExternalCrate" +# why use an attribute if a normal doc comment would suffice? +normalize_doc_attributes = true +# why not? +wrap_comments = true + +merge_derives = false ## I might need multi-line derives +overflow_delimited_expr = false +## When structs, slices, arrays, and block/array-like macros are used as the last argument in an +## expression list, allow them to overflow (like blocks/closures) instead of being indented on a new line. +reorder_impl_items = true +## Reorder impl items. type and const are put first, then macros and methods. diff --git a/src/main/java/com/utp/clsEstructuraDiscretas/pry3/DrawTable.java b/src/main/java/com/utp/clsEstructuraDiscretas/pry3/DrawTable.java index baf3a6a..c5f1c89 100644 --- a/src/main/java/com/utp/clsEstructuraDiscretas/pry3/DrawTable.java +++ b/src/main/java/com/utp/clsEstructuraDiscretas/pry3/DrawTable.java @@ -31,7 +31,7 @@ public String toString() { int ancho_columna = 0; for (String[] fila : this.table) { String celda = fila[indice_columna]; - if (celda.length() > ancho_columna) { + if (celda.length() >= ancho_columna) { // +1 para el caracter que encierra la celda ancho_columna = celda.length() + 1; columns_widths[indice_columna] = ancho_columna;