diff --git a/.github/linters/my_java_checkstyle.xml b/.github/linters/my_java_checkstyle.xml
new file mode 100644
index 00000000..82def407
--- /dev/null
+++ b/.github/linters/my_java_checkstyle.xml
@@ -0,0 +1,210 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml
new file mode 100644
index 00000000..ab9755d1
--- /dev/null
+++ b/.github/workflows/linter.yml
@@ -0,0 +1,41 @@
+---
+name: Lint
+
+on: # yamllint disable-line rule:truthy
+ push: null
+ pull_request: null
+
+jobs:
+ build:
+ name: Lint
+ runs-on: ubuntu-latest
+
+ permissions:
+ contents: read
+ packages: read
+ # To report GitHub Actions status checks
+ statuses: write
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+ with:
+ # super-linter needs the full git history to get the
+ # list of files that changed across commits
+ fetch-depth: 0
+
+ - name: Super-linter
+ uses: super-linter/super-linter@v5.7.2 # x-release-please-version
+ env:
+ DEFAULT_BRANCH: main
+ # To report GitHub Actions status checks
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ # Exclude forked files from checks
+ FILTER_REGEX_INCLUDE: .*src/.*
+ # Ignore .gitignore files
+ IGNORE_GITIGNORED_FILES: true
+
+ # Custom Java Checkstyle configuration
+ JAVA_FILE_NAME: my_java_checkstyle.xml
+ # Disable google-java-format
+ VALIDATE_GOOGLE_JAVA_FORMAT: false
diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 00000000..3e006c60
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1,10 @@
+{
+ "overrides": [
+ {
+ "files": "*.md",
+ "options": {
+ "tabWidth": 1
+ }
+ }
+ ]
+}
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 00000000..b315c3eb
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,11 @@
+{
+ "dotnet.defaultSolution": "RPG_Game/RPG_Game.sln",
+
+ "editor.formatOnSave": true,
+ "editor.defaultFormatter": "esbenp.prettier-vscode",
+
+ "[python]": {
+ "editor.defaultFormatter": "ms-python.black-formatter",
+ "editor.formatOnSave": true
+ }
+}
diff --git a/PYTHONREQUIREMENTS.md b/PYTHONREQUIREMENTS.md
new file mode 100644
index 00000000..ef8bc12a
--- /dev/null
+++ b/PYTHONREQUIREMENTS.md
@@ -0,0 +1,16 @@
+## To install all Python dependencies for any specific project:
+
+1. cd into the project folder.
+2. Ensure that the folder contains a `requirements.txt` file. This file contains all the necessary dependencies for this project to function.
+3. If this file is not found, look at `Creating a requirements.txt file for your project`. Else, go to step 4.
+4. Run the command `pip3 install -r requirements.txt` to generate the dependency file.
+
+
+
+## Creating a requirements.txt file for your project:
+
+1. We will use two libraries to help us generate the `requirements.txt` file - pipreqs and pip-tools.
+2. If not already installed, run `pip3 install pipreqs` and `pip3 install pip-tools`.
+3. cd into the project folder.
+4. Run the command `pipreqs --savepath=requirements.in && pip-compile`.
+5. Both `requirements.in` and `requirements.txt` files should be created.
\ No newline at end of file
diff --git a/README.md b/README.md
index 9f3119b7..28dd1082 100644
--- a/README.md
+++ b/README.md
@@ -155,7 +155,7 @@ To get started, simply fork this repo. Please refer to [CONTRIBUTING.md](CONTRIB
## C#:
-- [Learn C# By Building a Simple RPG Game](http://scottlilly.com/learn-c-by-building-a-simple-rpg-index/)
+- [Learn C# By Building a Simple RPG Game](http://scottlilly.com/learn-c-by-building-a-simple-rpg-index/) :white_check_mark:
- [Create a Rogue-like game in C#](https://roguesharp.wordpress.com/)
- [Create a Blank App with C# and Xamarin (work in progress)](https://www.intertech.com/Blog/xamarin-tutorial-part-1-create-a-blank-app/)
- [Build iOS Photo Library App with Xamarin and Visual Studio](https://www.raywenderlich.com/134049/building-ios-apps-with-xamarin-and-visual-studio)
@@ -371,7 +371,7 @@ To get started, simply fork this repo. Please refer to [CONTRIBUTING.md](CONTRIB
- [Mining Twitter Data with Python](https://marcobonzanini.com/2015/03/02/mining-twitter-data-with-python-part-1/)
- [Scrape a Website with Scrapy and MongoDB](https://realpython.com/blog/python/web-scraping-with-scrapy-and-mongodb/)
- [How To Scrape With Python and Selenium WebDriver](http://www.byperth.com/2018/04/25/guide-web-scraping-101-what-you-need-to-know-and-how-to-scrape-with-python-selenium-webdriver/)
-- [Which Movie Should I Watch using BeautifulSoup](https://medium.com/@nishantsahoo.in/which-movie-should-i-watch-5c83a3c0f5b1)
+- [Which Movie Should I Watch using BeautifulSoup](https://medium.com/@nishantsahoo.in/which-movie-should-i-watch-5c83a3c0f5b1) :white_check_mark:
### Web Applications:
@@ -401,7 +401,7 @@ To get started, simply fork this repo. Please refer to [CONTRIBUTING.md](CONTRIB
- [How to Make a Reddit Bot - YouTube](https://www.youtube.com/watch?v=krTUf7BpTc0) (video)
- [Build a Facebook Messenger Bot](https://blog.hartleybrody.com/fb-messenger-bot/)
- [Making a Reddit + Facebook Messenger Bot](https://pythontips.com/2017/04/13/making-a-reddit-facebook-messenger-bot/)
-- How To Create a Telegram Bot Using Python
+- How To Create a Telegram Bot Using Python :white_check_mark:
- [Part 1](https://khashtamov.com/en/how-to-create-a-telegram-bot-using-python/)
- [Part 2](https://khashtamov.com/en/how-to-deploy-telegram-bot-django/)
- [Create a Twitter Bot In Python](https://medium.freecodecamp.org/creating-a-twitter-bot-in-python-with-tweepy-ac524157a607)
diff --git a/src/Crafting_Interpreters/.gitignore b/src/Crafting_Interpreters/.gitignore
new file mode 100644
index 00000000..38105ec2
--- /dev/null
+++ b/src/Crafting_Interpreters/.gitignore
@@ -0,0 +1,24 @@
+# Compiled class file
+*.class
+
+# Log file
+*.log
+
+# BlueJ files
+*.ctxt
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.jar
+*.war
+*.nar
+*.ear
+*.zip
+*.tar.gz
+*.rar
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
+replay_pid*
\ No newline at end of file
diff --git a/src/Crafting_Interpreters/Makefile b/src/Crafting_Interpreters/Makefile
new file mode 100644
index 00000000..dcc2911c
--- /dev/null
+++ b/src/Crafting_Interpreters/Makefile
@@ -0,0 +1,41 @@
+JFLAGS = -g
+JC = javac
+
+.SUFFIXES: .java .class
+
+.java.class:
+ $(JC) $(JFLAGS) $*.java
+
+# This uses the line continuation character (\) for readability.
+# Compile .java files in dependency order.
+BASE_CLASSES = \
+ lox/TokenType.java \
+ lox/Token.java \
+ lox/Scanner.java \
+ lox/Lox.java \
+ tool/GenerateAst.java
+
+# These classes depend on generated classes.
+POST_CLASSES = \
+ lox/AstPrinter.java
+
+# All classes
+CLASSES = $(BASE_CLASSES) $(POST_CLASSES)
+
+default: build
+
+build: compile_base generate_ast compile_post
+
+compile_base: $(BASE_CLASSES:.java=.class)
+
+generate_ast: compile_base
+ java tool/GenerateAst lox
+
+compile_post: $(POST_CLASSES:.java=.class)
+
+clean:
+ find . -name "*.class" -type f -delete
+ $(RM) lox/Expr.java
+
+run: build
+ java lox/Lox
diff --git a/src/Crafting_Interpreters/README.md b/src/Crafting_Interpreters/README.md
new file mode 100644
index 00000000..3915c27b
--- /dev/null
+++ b/src/Crafting_Interpreters/README.md
@@ -0,0 +1,15 @@
+# Build an Interpreter
+
+Date Started: 07/01/2024
+
+Date Completed:
+
+This is a mini-project to learn about how compilers work by attempting to implement one in Java programming language. Here is the [link](https://www.craftinginterpreters.com/contents.html) to the guide that I followed. Stopped at Chapter 6.
+
+Dependencies:
+
+-
+
+References:
+
+-
diff --git a/src/Crafting_Interpreters/lox/AstPrinter.java b/src/Crafting_Interpreters/lox/AstPrinter.java
new file mode 100644
index 00000000..687f98b7
--- /dev/null
+++ b/src/Crafting_Interpreters/lox/AstPrinter.java
@@ -0,0 +1,42 @@
+package lox;
+
+class AstPrinter implements Expr.Visitor {
+ String print(Expr expr) {
+ return expr.accept(this);
+ }
+
+ @Override
+ public String visitBinaryExpr(Expr.Binary expr) {
+ return parenthesize(expr.operator.getLexeme(),
+ expr.left, expr.right);
+ }
+
+ @Override
+ public String visitGroupingExpr(Expr.Grouping expr) {
+ return parenthesize("group", expr.expression);
+ }
+
+ @Override
+ public String visitLiteralExpr(Expr.Literal expr) {
+ if (expr.value == null) return "nil";
+ return expr.value.toString();
+ }
+
+ @Override
+ public String visitUnaryExpr(Expr.Unary expr) {
+ return parenthesize(expr.operator.getLexeme(), expr.right);
+ }
+
+ private String parenthesize(String name, Expr... exprs) {
+ StringBuilder builder = new StringBuilder();
+
+ builder.append("(").append(name);
+ for (Expr expr : exprs) {
+ builder.append(" ");
+ builder.append(expr.accept(this));
+ }
+ builder.append(")");
+
+ return builder.toString();
+ }
+}
diff --git a/src/Crafting_Interpreters/lox/Lox.java b/src/Crafting_Interpreters/lox/Lox.java
new file mode 100644
index 00000000..b19dc0f4
--- /dev/null
+++ b/src/Crafting_Interpreters/lox/Lox.java
@@ -0,0 +1,98 @@
+package lox;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.List;
+
+public final class Lox {
+ /**
+ * A flag to indicate if an error occurred
+ * during the execution of the program.
+ */
+ private static boolean hadError = false;
+
+ /**
+ * The exit code to indicate a usage error.
+ */
+ private static final int EX_USAGE = 64;
+
+ /**
+ * The exit code to indicate a data error.
+ */
+ private static final int EX_DATAERR = 65;
+
+
+ /**
+ * Private constructor to prevent instantiation of this class.
+ */
+ private Lox() { }
+
+ /**
+ * The entry point of the program.
+ *
+ * @param args The command line arguments.
+ * @throws IOException If an I/O error occurs.
+ */
+ public static void main(String[] args) throws IOException {
+ if (args.length > 1) {
+ System.out.println("Usage: jlox [script]");
+ System.exit(EX_USAGE);
+ } else if (args.length == 1) {
+ runFile(args[0]);
+ } else {
+ runPrompt();
+ }
+ }
+
+ private static void runFile(String path) throws IOException {
+ byte[] bytes = Files.readAllBytes(Paths.get(path));
+ run(new String(bytes, Charset.defaultCharset()));
+
+ // Indicate an error in the exit code.
+ if (hadError) System.exit(EX_DATAERR);
+ }
+
+ private static void runPrompt() throws IOException {
+ InputStreamReader input = new InputStreamReader(System.in);
+ BufferedReader reader = new BufferedReader(input);
+
+ for (;;) {
+ System.out.print("> ");
+ String line = reader.readLine();
+ if (line == null) break;
+ run(line);
+ hadError = false;
+ }
+ }
+
+ private static void run(String source) {
+ Scanner scanner = new Scanner(source);
+ List tokens = scanner.scanTokens();
+
+ // For now, just print the tokens.
+ for (Token token : tokens) {
+ System.out.println(token);
+ }
+ }
+
+ /**
+ * Report an error.
+ *
+ * @param line The line number where the error occurred.
+ * @param message The error message.
+ */
+ public static void error(int line, String message) {
+ report(line, "", message);
+ }
+
+ private static void report(int line, String where, String message) {
+ String msg = String.format("[line %d] Error%s: %s",
+ line, where, message);
+ System.err.println(msg);
+ hadError = true;
+ }
+}
diff --git a/src/Crafting_Interpreters/lox/Scanner.java b/src/Crafting_Interpreters/lox/Scanner.java
new file mode 100644
index 00000000..ccdc6e88
--- /dev/null
+++ b/src/Crafting_Interpreters/lox/Scanner.java
@@ -0,0 +1,236 @@
+package lox;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static lox.TokenType.*;
+
+class Scanner {
+
+ /**
+ * A map of KEYWORDS to their respective token types.
+ */
+ private static final Map KEYWORDS;
+
+ static {
+ KEYWORDS = new HashMap<>();
+ KEYWORDS.put("and", AND);
+ KEYWORDS.put("class", CLASS);
+ KEYWORDS.put("else", ELSE);
+ KEYWORDS.put("false", FALSE);
+ KEYWORDS.put("for", FOR);
+ KEYWORDS.put("fun", FUN);
+ KEYWORDS.put("if", IF);
+ KEYWORDS.put("nil", NIL);
+ KEYWORDS.put("or", OR);
+ KEYWORDS.put("print", PRINT);
+ KEYWORDS.put("return", RETURN);
+ KEYWORDS.put("super", SUPER);
+ KEYWORDS.put("this", THIS);
+ KEYWORDS.put("true", TRUE);
+ KEYWORDS.put("var", VAR);
+ KEYWORDS.put("while", WHILE);
+ }
+
+ /**
+ * The source code to scan.
+ */
+ private final String source;
+
+ /**
+ * The list of tokens found in the source code.
+ */
+ private final List tokens = new ArrayList<>();
+
+ /**
+ * The index of the first character in the current lexeme.
+ */
+ private int start = 0;
+
+ /**
+ * The index of the current character being considered.
+ */
+ private int current = 0;
+
+ /**
+ * The current line number in the source code.
+ */
+ private int line = 1;
+
+
+ /**
+ * Create a new scanner for the specified source code.
+ *
+ * @param source The source code to scan.
+ */
+ Scanner(String source) {
+ this.source = source;
+ }
+
+ /**
+ * Scan the source code and return the list of tokens found.
+ *
+ * @return The list of tokens found in the source code.
+ */
+ List scanTokens() {
+ while (!isAtEnd()) {
+ // We are at the beginning of the next lexeme.
+ start = current;
+ scanToken();
+ }
+
+ tokens.add(new Token(EOF, "", null, line));
+ return tokens;
+ }
+
+ private void scanToken() {
+ char c = advance();
+ switch (c) {
+ case '(': addToken(LEFT_PAREN); break;
+ case ')': addToken(RIGHT_PAREN); break;
+ case '{': addToken(LEFT_BRACE); break;
+ case '}': addToken(RIGHT_BRACE); break;
+ case ',': addToken(COMMA); break;
+ case '.': addToken(DOT); break;
+ case '-': addToken(MINUS); break;
+ case '+': addToken(PLUS); break;
+ case ';': addToken(SEMICOLON); break;
+ case '*': addToken(STAR); break;
+ case '!':
+ addToken(match('=') ? BANG_EQUAL : BANG);
+ break;
+ case '=':
+ addToken(match('=') ? EQUAL_EQUAL : EQUAL);
+ break;
+ case '<':
+ addToken(match('=') ? LESS_EQUAL : LESS);
+ break;
+ case '>':
+ addToken(match('=') ? GREATER_EQUAL : GREATER);
+ break;
+ case '/':
+ if (match('/')) {
+ // A comment goes until the end of the line.
+ while (peek() != '\n' && !isAtEnd()) advance();
+ } else {
+ addToken(SLASH);
+ }
+ break;
+ case ' ':
+ case '\r':
+ case '\t':
+ // Ignore whitespace.
+ break;
+
+ case '\n':
+ line++;
+ break;
+
+ case '"': string(); break;
+
+ default:
+ if (isDigit(c)) {
+ number();
+ } else if (isAlpha(c)) {
+ identifier();
+ } else {
+ Lox.error(line, "Unexpected character.");
+ }
+ break;
+ }
+ }
+
+ private void string() {
+ while (peek() != '"' && !isAtEnd()) {
+ if (peek() == '\n') line++;
+ advance();
+ }
+
+ // Unterminated string.
+ if (isAtEnd()) {
+ Lox.error(line, "Unterminated string.");
+ return;
+ }
+
+ // The closing ".
+ advance();
+
+ // Trim the surrounding quotes.
+ String value = source.substring(start + 1, current - 1);
+ addToken(STRING, value);
+ }
+
+ private void number() {
+ while (isDigit(peek())) advance();
+
+ // Look for a fractional part.
+ if (peek() == '.' && isDigit(peekNext())) {
+ // Consume the "."
+ advance();
+
+ while (isDigit(peek())) advance();
+ }
+
+ addToken(NUMBER, Double.parseDouble(source.substring(start, current)));
+ }
+
+ private void identifier() {
+ while (isAlphaNumeric(peek())) advance();
+
+ String text = source.substring(start, current);
+ TokenType type = KEYWORDS.get(text);
+ if (type == null) type = IDENTIFIER;
+ addToken(type);
+ }
+
+ private boolean match(char expected) {
+ if (isAtEnd()) return false;
+ if (source.charAt(current) != expected) return false;
+
+ current++;
+ return true;
+ }
+
+ private char peek() {
+ if (isAtEnd()) return '\0';
+ return source.charAt(current);
+ }
+
+ private char peekNext() {
+ if (current + 1 >= source.length()) return '\0';
+ return source.charAt(current + 1);
+ }
+
+ private boolean isDigit(char c) {
+ return c >= '0' && c <= '9';
+ }
+
+ private boolean isAlpha(char c) {
+ return (c >= 'a' && c <= 'z')
+ || (c >= 'A' && c <= 'Z')
+ || c == '_';
+ }
+
+ private boolean isAlphaNumeric(char c) {
+ return isAlpha(c) || isDigit(c);
+ }
+
+ private boolean isAtEnd() {
+ return current >= source.length();
+ }
+
+ private char advance() {
+ return source.charAt(current++);
+ }
+
+ private void addToken(TokenType type) {
+ addToken(type, null);
+ }
+
+ private void addToken(TokenType type, Object literal) {
+ String text = source.substring(start, current);
+ tokens.add(new Token(type, text, literal, line));
+ }
+}
diff --git a/src/Crafting_Interpreters/lox/Token.java b/src/Crafting_Interpreters/lox/Token.java
new file mode 100644
index 00000000..2335741c
--- /dev/null
+++ b/src/Crafting_Interpreters/lox/Token.java
@@ -0,0 +1,58 @@
+package lox;
+
+class Token {
+ /**
+ * The type of the token.
+ */
+ private final TokenType type;
+
+ /**
+ * The lexeme of the token.
+ */
+ private final String lexeme;
+
+ /**
+ * The literal value of the token.
+ */
+ private final Object literal;
+
+ /**
+ * The line number in the source code where the token appears.
+ */
+ private final int line;
+
+
+ /**
+ * Create a new token.
+ *
+ * @param type The type of the token.
+ * @param lexeme The lexeme of the token.
+ * @param literal The literal value of the token.
+ * @param line The line number in the source code where the token appears.
+ */
+ Token(TokenType type, String lexeme, Object literal, int line) {
+ this.type = type;
+ this.lexeme = lexeme;
+ this.literal = literal;
+ this.line = line;
+ }
+
+ /**
+ * Return a string representation of the token.
+ *
+ * @return A string representation of the token.
+ */
+ @Override
+ public String toString() {
+ return type + " " + lexeme + " " + literal;
+ }
+
+ /**
+ * Gets the lexeme.
+ *
+ * @return The lexeme.
+ */
+ public String getLexeme() {
+ return lexeme;
+ }
+}
diff --git a/src/Crafting_Interpreters/lox/TokenType.java b/src/Crafting_Interpreters/lox/TokenType.java
new file mode 100644
index 00000000..92dd3fcc
--- /dev/null
+++ b/src/Crafting_Interpreters/lox/TokenType.java
@@ -0,0 +1,23 @@
+package lox;
+
+@SuppressWarnings("checkstyle:JavadocVariable")
+enum TokenType {
+ // Single-character tokens.
+ LEFT_PAREN, RIGHT_PAREN, LEFT_BRACE, RIGHT_BRACE,
+ COMMA, DOT, MINUS, PLUS, SEMICOLON, SLASH, STAR,
+
+ // One or two character tokens.
+ BANG, BANG_EQUAL,
+ EQUAL, EQUAL_EQUAL,
+ GREATER, GREATER_EQUAL,
+ LESS, LESS_EQUAL,
+
+ // Literals.
+ IDENTIFIER, STRING, NUMBER,
+
+ // Keywords.
+ AND, CLASS, ELSE, FALSE, FUN, FOR, IF, NIL, OR,
+ PRINT, RETURN, SUPER, THIS, TRUE, VAR, WHILE,
+
+ EOF
+}
diff --git a/src/Crafting_Interpreters/tool/GenerateAst.java b/src/Crafting_Interpreters/tool/GenerateAst.java
new file mode 100644
index 00000000..cb2f8bd3
--- /dev/null
+++ b/src/Crafting_Interpreters/tool/GenerateAst.java
@@ -0,0 +1,111 @@
+package tool;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Arrays;
+import java.util.List;
+
+public final class GenerateAst {
+ // Make the constructor private.
+ private GenerateAst() {
+ throw new AssertionError("Cannot instantiate utility class.");
+ }
+
+ /**
+ * Defines the structure of AST classes.
+ *
+ * @param args The command line arguments. The first argument is the output
+ * directory.
+ * @throws IOException If an I/O error occurs.
+ */
+ public static void main(String[] args) throws IOException {
+ if (args.length != 1) {
+ System.err.println("Usage: generate_ast