agentscape
Version:
Agentscape is a library for creating agent-based simulations. It provides a simple API for defining agents and their behavior, and for defining the environment in which the agents interact. Agentscape is designed to be flexible and extensible, allowing
184 lines (147 loc) • 3.9 kB
text/typescript
export class LinkedListNode<T> {
constructor(
public value: T,
public next: LinkedListNode<T> | undefined = undefined,
public previous: LinkedListNode<T> | undefined = undefined
) {}
}
export default class LinkedList<T> {
// the element at the start of the list
public head: LinkedListNode<T> | undefined = undefined
// the element at the end of the list
public tail: LinkedListNode<T> | undefined = undefined
// the number of elements in the list
public size: number = 0
constructor() {}
/**
* Iterates over the elements of the list
*/
public *[Symbol.iterator]() {
let current = this.head
while (current) {
yield current
current = current.next
}
}
public forEach(callback: (value: LinkedListNode<T>) => void) {
let current = this.head
while (current) {
callback(current)
current = current.next
}
}
/**
* Inserts an element at the end of the list
* @param value
*/
public append(value: T) {
const node = new LinkedListNode(value)
if (!this.head) {
this.head = node
this.tail = node
} else {
this.tail!.next = node
node.previous = this.tail
this.tail = node
}
this.size++
}
/**
* Inserts an element at the start of the list
* @param value
*/
public prepend(value: T) {
const node = new LinkedListNode(value)
if (!this.head) {
this.head = node
this.tail = node
} else {
this.head.previous = node
node.next = this.head
this.head = node
}
this.size++
}
/**
* Removes the first element from the list
*/
public dropFirst() {
if (!this.head) {
return
}
this.head = this.head.next
if (this.head) {
this.head.previous = undefined
} else {
this.tail = undefined
}
this.size--
}
/**
* Removes the last element from the list
*/
public dropLast() {
if (!this.tail) {
return
}
this.tail = this.tail.previous
if (this.tail) {
this.tail.next = undefined
} else {
this.head = undefined
}
this.size--
}
/**
* Inserts an element at a specific location in the list
*/
public insertAt(index: number, value: T) {
if (index < 0 || index > this.size) {
throw new Error('Index out of bounds')
}
if (index === 0) {
this.prepend(value)
return
}
if (index === this.size) {
this.append(value)
return
}
let current = this.head
for (let i = 0; i < index - 1; i++) {
current = current!.next
}
const node = new LinkedListNode(value)
node.next = current!.next
node.previous = current
current!.next!.previous = node
current!.next = node
this.size++
}
public find(value: T) {
let current = this.head
while (current) {
if (current.value === value) {
return current
}
current = current.next
}
return null
}
public toArray() {
const array: T[] = []
let current = this.head
while (current) {
array.push(current.value)
current = current.next
}
return array
}
public static fromArray<T>(array: T[]) {
const list = new LinkedList<T>()
for (const element of array) {
list.append(element)
}
return list
}
}