Compare commits

...

4 Commits

Author SHA1 Message Date
Tristan B. Velloza Kildaire 67d8af2954
Merge 4a431c43d1 into 0e232822fa 2024-04-26 14:36:47 +00:00
Tristan B. Velloza Kildaire 4a431c43d1 TreeNode
- Added removal
- Added indexing support
2024-04-26 16:35:21 +02:00
Tristan B. Velloza Kildaire 11fd2f856e Methods
- Added leftwards shifting mechanism
2024-04-26 16:28:19 +02:00
Tristan B. Velloza Kildaire 0e232822fa
Feature: Prompting framework (#16)
* Prompter

- Added

Prompt

- Added

* Prompter

- Fixed source `File` check

Prompter (unittests)

- Added a unittest

* Prompter

- Fixed `prompt()`

Prompter (unittests)

- `flush()` pipe write end

* Prompter (unittests)

- Cleaned up

* Prompter (unittests)

- Cleaned up

* Prompter (unittests)

- Fixed missing import

* Prompter

- Added more docs

* Prompter

- Added more docs

* Prompt

- Documented

* Prompter

- Cleand up

* Prompter (unittests)

- Removed unittest

* README

- Updated
2024-04-15 10:45:16 +02:00
3 changed files with 289 additions and 16 deletions

View File

@ -40,6 +40,8 @@ is expected to grow over time.
* `niknaks.containers`
* Some useful container types
* Things such as `CacheMap`
* `niknaks.mechanisms`
* User-defined input prompter, retry mechanisms
## License

View File

@ -596,7 +596,7 @@ unittest
// then 0 moves into 1's place
// 0's position is then filled with T.init
public T[] shift(T)(T[] array, size_t position, bool rightwards = false, bool shrink = false)
public T[] shiftInto(T)(T[] array, size_t position, bool rightwards = false, bool shrink = false)
{
// Out of range
if(position >= array.length)
@ -629,6 +629,32 @@ public T[] shift(T)(T[] array, size_t position, bool rightwards = false, bool sh
array = array[1..$];
}
}
// if leftwards
else
{
// nothing furtherright
if(position == array.length-1)
{
return array;
}
for(size_t i = position; i < array.length-1; i++)
{
array[i] = array[i+1];
}
// no shrink, then fill with T.init
if(!shrink)
{
array[$-1] = T.init;
}
// chomp right-hand side
else
{
array = array[0..$-1];
}
}
return array;
}
@ -637,57 +663,83 @@ public T[] shift(T)(T[] array, size_t position, bool rightwards = false, bool sh
unittest
{
int[] numbas = [1, 5, 2];
numbas = numbas.shift(1, true);
numbas = numbas.shiftInto(1, true);
// should now be [0, 1, 2]
writeln(numbas);
assert(numbas == [0, 1, 2]);
numbas = [1, 5, 2];
numbas = numbas.shift(0, true);
numbas = numbas.shiftInto(0, true);
// should now be [1, 5, 2]
writeln(numbas);
assert(numbas == [1, 5, 2]);
numbas = [1, 5, 2];
numbas = numbas.shift(2, true);
numbas = numbas.shiftInto(2, true);
// should now be [0, 1, 5]
writeln(numbas);
assert(numbas == [0, 1, 5]);
numbas = [1, 2];
numbas = numbas.shift(1, true);
numbas = numbas.shiftInto(1, true);
// should now be [0, 1]
writeln(numbas);
assert(numbas == [0, 1]);
numbas = [1, 2];
numbas = numbas.shift(0, true);
numbas = numbas.shiftInto(0, true);
// should now be [1, 2]
writeln(numbas);
assert(numbas == [1, 2]);
numbas = [];
numbas = numbas.shift(0, true);
numbas = numbas.shiftInto(0, false);
// should now be []
writeln(numbas);
assert(numbas == []);
}
public T[] remove(T)(T[] array, size_t idx)
// leftwards testung (no shrink)
unittest
{
// Return your array on this
if(!(idx < array.length))
{
return array;
}
int[] numbas = [1, 5, 2];
numbas = numbas.shiftInto(1, false);
return null;
// should now be [1, 2, 0]
writeln(numbas);
assert(numbas == [1, 2, 0]);
numbas = [1, 5, 2];
numbas = numbas.shiftInto(0, false);
// should now be [5, 2, 0]
writeln(numbas);
assert(numbas == [5, 2, 0]);
numbas = [1, 5, 2];
numbas = numbas.shiftInto(2, false);
// should now be [1, 5, 2]
writeln(numbas);
assert(numbas == [1, 5, 2]);
numbas = [];
numbas = numbas.shiftInto(0, true);
// should now be []
writeln(numbas);
assert(numbas == []);
}
public T[] removeResize(T)(T[] array, size_t position)
{
return array.shiftInto(position, false, true);
}
// TODO: make delegate kak
@ -767,16 +819,34 @@ public class Tree(T)
public bool removeNode(Tree!(T) node)
{
bool found = false;
size_t idx;
for(size_t i = 0; i < this.children.length; i++)
{
found = this.children[i] == node;
if(found)
{
idx = i;
break;
}
}
return true;
if(found)
{
this.children = this.children.removeResize(idx);
return true;
}
return false;
}
public T opIndex(size_t idx)
{
return idx < this.children.length ? this.children[idx].getValue() : T.init;
}
public T getValue()
{
return this.value;
}
public T[] dfs

View File

@ -9,6 +9,8 @@ import std.functional : toDelegate;
import std.datetime : Duration;
import std.datetime.stopwatch : StopWatch, AutoStart;
import core.thread : Thread;
import std.stdio : File, write;
import std.string : strip;
/**
* A verdict-providing function
@ -291,4 +293,203 @@ unittest
}
}
/**
* A user-defined prompt
*/
public struct Prompt
{
private string query;
private string value;
/**
* Constructs a new prompt
* with the given query
*
* Params:
* query = the prompt
* query itself
*/
this(string query)
{
this.query = query;
}
/**
* Gets the prompt query
*
* Returns: the query
*/
public string getQuery()
{
return this.query;
}
/**
* Retrieves this prompt's
* answer
*
* Returns: the answer
*/
public string getValue()
{
return this.value;
}
/**
* Fill this prompt's
* query with a corresponding
* answer
*
* Params:
* value = the answer
*/
public void fill(string value)
{
this.value = value;
}
}
/**
* A prompting mechanism
* which can be filled up
* with questions and a
* file-based source to
* read answers in from
* and associate with
* their original respective
* questions
*/
public class Prompter
{
/**
* Source file
*/
private File source;
/**
* Whether or not to close
* the source file on destruction
*/
private bool closeOnDestruct;
/**
* Prompts to query by
*/
private Prompt[] prompts;
/**
* Constructs a new prompter
* with the given file source
* from where the input is to
* be read from.
*
* Params:
* source = the `File` to
* read from
* closeOnDestruct = if
* set to `true` then on
* destruction we will close
* the source, if `false` it
* is left untouched
*
* Throws:
* Exception if the provided
* `File` is not open
*/
this(File source, bool closeOnDestruct = false)
{
if(!source.isOpen())
{
throw new Exception("Source not open");
}
this.closeOnDestruct = closeOnDestruct;
this.source = source;
}
/**
* Appends the given prompt
*
* Params:
* prompt = the prompt
*/
public void addPrompt(Prompt prompt)
{
this.prompts ~= prompt;
}
/**
* Performs the prompting
* by querying each attached
* prompt for an answer
* which is then associated
* with the given prompt
*
* Returns: the answered
* prompts
*/
public Prompt[] prompt()
{
char[] buff;
foreach(ref Prompt prompt; this.prompts)
{
scope(exit)
{
buff.length = 0;
}
// Perform the query
write(prompt.getQuery());
this.source.readln(buff);
// Fill answer into prompt
prompt.fill(strip(cast(string)buff));
}
return this.prompts;
}
/**
* Destructor
*/
~this()
{
if(this.closeOnDestruct)
{
this.source.close();
}
}
}
version(unittest)
{
import std.process : pipe, Pipe;
import std.conv : to;
import std.stdio : writeln;
}
unittest
{
Pipe pipe = pipe();
// Create a prompter with some prompts
Prompter p = new Prompter(pipe.readEnd());
p.addPrompt(Prompt("What is your name?"));
p.addPrompt(Prompt("How old are you"));
// Fill up pipe with data for read end
File writeEnd = pipe.writeEnd();
writeEnd.writeln("Tristan Brice Velloza Kildaire");
writeEnd.writeln(1);
writeEnd.flush();
// Perform the prompt and get the
// answers back out
Prompt[] ans = p.prompt();
writeln(ans);
assert(ans[0].getValue() == "Tristan Brice Velloza Kildaire");
assert(to!(int)(ans[1].getValue()) == 1); // TODO: Allow union conversion later
}