feat: added run sh and makefile scripts

This commit is contained in:
Krzysztof kuhy Rudnicki 2026-02-22 22:00:50 +01:00
parent c544aae70c
commit 5a8be96f94
86 changed files with 1453 additions and 66 deletions

View File

@ -0,0 +1,19 @@
CC := gcc
CFLAGS := -O2 -Wall -Wextra -std=c11 -D_DEFAULT_SOURCE
LDFLAGS :=
SRC := main.c
BIN := 1dvelocitysimulator
all: $(BIN)
$(BIN): $(SRC)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
run: $(BIN)
./$(BIN)
clean:
rm -f $(BIN)
.PHONY: all run clean

View File

@ -1,7 +1,24 @@
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef _WIN32
#include <windows.h>
#define SLEEP_MS(ms) Sleep(ms)
#define CLEAR_SCREEN() system("CLS")
#define PAUSE() system("PAUSE")
#else
#include <unistd.h>
#define SLEEP_MS(ms) usleep((ms) * 1000U)
#define CLEAR_SCREEN() system("clear")
#define PAUSE() \
do \
{ \
printf("Press Enter to continue..."); \
getchar(); \
} while (0)
#endif
#define LINE_LENGTH 100
void C()
@ -13,27 +30,27 @@ void C()
void printAcceleration(int acceleration)
{
printf("The value of acceleration is: %d\n", acceleration);
system("PAUSE");
PAUSE();
return;
}
void pauseSystem() { system("PAUSE"); }
void pauseSystem() { PAUSE(); }
void clearScreen()
{
system("CLS");
CLEAR_SCREEN();
return;
}
void pauseForASecond()
{
Sleep(1000);
SLEEP_MS(1000);
return;
}
void pauseForGivenTime(float given_time)
{
Sleep(fabs(given_time * 1000));
SLEEP_MS((unsigned int)fabs(given_time * 1000));
return;
}

4
C/1dvelocitysimulator/run.sh Executable file
View File

@ -0,0 +1,4 @@
#!/usr/bin/env bash
set -e
make
./1dvelocitysimulator

12
C/fps/run.sh Executable file
View File

@ -0,0 +1,12 @@
#!/usr/bin/env bash
set -e
# Install dependencies
if command -v apt-get &>/dev/null; then
sudo apt-get install -y freeglut3-dev libglu1-mesa-dev libsdl2-dev
elif command -v pacman &>/dev/null; then
pacman -Q freeglut sdl2 &>/dev/null || sudo pacman -S --noconfirm freeglut sdl2
elif command -v dnf &>/dev/null; then
sudo dnf install -y freeglut-devel mesa-libGLU-devel SDL2-devel
fi
make
./fps_demo

15
C/imageViewer/run.sh Executable file
View File

@ -0,0 +1,15 @@
#!/usr/bin/env bash
set -e
# Install dependencies
if command -v apt-get &>/dev/null; then
sudo apt-get install -y libsdl2-dev libsdl2-image-dev
elif command -v pacman &>/dev/null; then
pacman -Q sdl2 sdl2_image &>/dev/null || sudo pacman -S --noconfirm sdl2 sdl2_image
elif command -v dnf &>/dev/null; then
sudo dnf install -y SDL2-devel SDL2_image-devel
fi
make
echo "Usage: ./imageviewer <image_file>"
if [[ $# -gt 0 ]]; then
./imageviewer "$@"
fi

5
C/lichess_random_engine/run.sh Executable file
View File

@ -0,0 +1,5 @@
#!/usr/bin/env bash
set -e
make
echo "Usage: ./random_engine --fen \"<FEN>\" move1 move2 ..."
echo " ./random_engine --fen \"<FEN>\" --explain move1 ..."

19
C/misc/Makefile Normal file
View File

@ -0,0 +1,19 @@
CC := gcc
CFLAGS := -O2 -Wall -Wextra -std=c11
LDFLAGS :=
SRC := generatingWordsEndingWIthalka.c
BIN := generating_words
all: $(BIN)
$(BIN): $(SRC)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
run: $(BIN)
./$(BIN)
clean:
rm -f $(BIN)
.PHONY: all run clean

12
C/misc/randomJPG/run.sh Executable file
View File

@ -0,0 +1,12 @@
#!/usr/bin/env bash
set -e
# Install dependencies
if command -v apt-get &>/dev/null; then
sudo apt-get install -y libjpeg-dev
elif command -v pacman &>/dev/null; then
pacman -Q libjpeg-turbo &>/dev/null || sudo pacman -S --noconfirm libjpeg-turbo
elif command -v dnf &>/dev/null; then
sudo dnf install -y libjpeg-turbo-devel
fi
make
./generate_images

4
C/misc/run.sh Executable file
View File

@ -0,0 +1,4 @@
#!/usr/bin/env bash
set -e
make
./generating_words

19
C/misc/split/Makefile Normal file
View File

@ -0,0 +1,19 @@
CC := gcc
CFLAGS := -O2 -Wall -Wextra -std=c11
LDFLAGS :=
SRC := main.c
BIN := split
all: $(BIN)
$(BIN): $(SRC)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
run: $(BIN)
./$(BIN)
clean:
rm -f $(BIN)
.PHONY: all run clean

4
C/misc/split/run.sh Executable file
View File

@ -0,0 +1,4 @@
#!/usr/bin/env bash
set -e
make
./split

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -14,7 +14,7 @@ if ! command -v sdl2-config >/dev/null 2>&1; then
sudo apt-get install -y libsdl2-dev
;;
arch|manjaro|endeavouros)
sudo pacman -Syu --noconfirm sdl2
pacman -Q sdl2 &>/dev/null || sudo pacman -S --noconfirm sdl2
;;
fedora)
sudo dnf install -y SDL2-devel

19
C/scrapeWebsite/Makefile Normal file
View File

@ -0,0 +1,19 @@
CC := gcc
CFLAGS := -O2 -Wall -Wextra -std=c11 -D_DEFAULT_SOURCE $(shell pkg-config --cflags libcurl libxml-2.0 2>/dev/null)
LDFLAGS := $(shell pkg-config --libs libcurl libxml-2.0 2>/dev/null)
SRC := scrape.c
BIN := scrape
all: $(BIN)
$(BIN): $(SRC)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
run: $(BIN)
./$(BIN)
clean:
rm -f $(BIN)
.PHONY: all run clean

12
C/scrapeWebsite/run.sh Executable file
View File

@ -0,0 +1,12 @@
#!/usr/bin/env bash
set -e
# Install dependencies
if command -v apt-get &>/dev/null; then
sudo apt-get install -y libcurl4-openssl-dev libxml2-dev
elif command -v pacman &>/dev/null; then
pacman -Q curl libxml2 &>/dev/null || sudo pacman -S --noconfirm curl libxml2
elif command -v dnf &>/dev/null; then
sudo dnf install -y libcurl-devel libxml2-devel
fi
make
./scrape

19
C/tests/Makefile Normal file
View File

@ -0,0 +1,19 @@
CC := gcc
CFLAGS := -O2 -Wall -Wextra -std=c11 -D_DEFAULT_SOURCE
LDFLAGS :=
SRC := generatingPolishLettersOnWindowsTerminal.c
BIN := polish_letters
all: $(BIN)
$(BIN): $(SRC)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
run: $(BIN)
./$(BIN)
clean:
rm -f $(BIN)
.PHONY: all run clean

View File

@ -1,10 +1,17 @@
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
int main()
#ifdef _WIN32
#include <windows.h>
#define SLEEP_S(s) Sleep((s) * 1000)
#else
#include <unistd.h>
#define SLEEP_S(s) sleep(s)
#endif
int main(void)
{
printf("Henlo\n");
sleep(20);
SLEEP_S(20);
return 0;
}

4
C/tests/run.sh Executable file
View File

@ -0,0 +1,4 @@
#!/usr/bin/env bash
set -e
make
./polish_letters

4
C/vocabulary_curve/run.sh Executable file
View File

@ -0,0 +1,4 @@
#!/usr/bin/env bash
set -e
make
./vocabulary_curve

Binary file not shown.

View File

@ -0,0 +1,19 @@
CC := gcc
CFLAGS := -O2 -Wall -Wextra -std=c11 $(shell pkg-config --cflags libwebsockets 2>/dev/null)
LDFLAGS := $(shell pkg-config --libs libwebsockets 2>/dev/null)
SRC := main.c
BIN := websocket_server
all: $(BIN)
$(BIN): $(SRC)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
run: $(BIN)
./$(BIN)
clean:
rm -f $(BIN)
.PHONY: all run clean

17
C/websocketServer/run.sh Executable file
View File

@ -0,0 +1,17 @@
#!/usr/bin/env bash
set -e
# Install dependencies
if command -v pacman &>/dev/null; then
pacman -Q libwebsockets &>/dev/null || sudo pacman -S --noconfirm libwebsockets
elif command -v apt-get &>/dev/null; then
sudo apt-get install -y libwebsockets-dev
elif command -v dnf &>/dev/null; then
sudo dnf install -y libwebsockets-devel
elif command -v zypper &>/dev/null; then
sudo zypper install -y libwebsockets-devel
else
echo "Could not detect package manager. Please install libwebsockets manually." >&2
exit 1
fi
make
./websocket_server

30
CPP/miscelanious/Makefile Normal file
View File

@ -0,0 +1,30 @@
CXX := g++
CXXFLAGS := -O2 -Wall -Wextra -std=c++17
LDFLAGS :=
BINS := howOftenDoesCharOccur quickchallenges reverseString solveQuadraticEquation
all: $(BINS)
howOftenDoesCharOccur: howOftenDoesCharOccur.cpp
$(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS)
quickchallenges: quickchallenges.cpp
$(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS)
reverseString: reverseString.cpp
$(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS)
solveQuadraticEquation: solveQuadraticEquation.cpp
$(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS)
run: all
./howOftenDoesCharOccur
./quickchallenges
./reverseString
./solveQuadraticEquation
clean:
rm -f $(BINS)
.PHONY: all run clean

View File

@ -0,0 +1,19 @@
CXX := g++
CXXFLAGS := -O2 -Wall -Wextra -std=c++17
LDFLAGS := -lm
SRC := main.cpp
BIN := pi
all: $(BIN)
$(BIN): $(SRC)
$(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS)
run: $(BIN)
./$(BIN)
clean:
rm -f $(BIN)
.PHONY: all run clean

4
CPP/miscelanious/Pi/run.sh Executable file
View File

@ -0,0 +1,4 @@
#!/usr/bin/env bash
set -e
make
./pi

View File

@ -0,0 +1,19 @@
CXX := g++
CXXFLAGS := -O2 -Wall -Wextra -std=c++17
LDFLAGS :=
SRC := brydz.cpp
BIN := brydz
all: $(BIN)
$(BIN): $(SRC)
$(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS)
run: $(BIN)
./$(BIN)
clean:
rm -f $(BIN)
.PHONY: all run clean

View File

@ -4,7 +4,7 @@
const std::vector<std::string> ATUTY = {"BA", "Trefl", "Karo", "Kier", "Pik"};
const bool A_ID = 0;
const bool B_ID = 1;
const std::vector<std::string> GRACZE = {};
const std::vector<std::string> GRACZE = {"Gracz A", "Gracz B"};
const std::vector<std::string> PO_PARTII{"Nikt", GRACZE[A_ID], GRACZE[B_ID],
"Obaj Gracze"};
const int DOMYSLNE_LEWY = 6;

4
CPP/miscelanious/brydz/run.sh Executable file
View File

@ -0,0 +1,4 @@
#!/usr/bin/env bash
set -e
make
./brydz

View File

@ -0,0 +1,20 @@
CXX := g++
CXXFLAGS := -O2 -Wall -Wextra -std=c++17
LDFLAGS :=
# main.cpp includes basic.cpp directly
SRC := main.cpp
BIN := darts
all: $(BIN)
$(BIN): $(SRC)
$(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS)
run: $(BIN)
./$(BIN)
clean:
rm -f $(BIN)
.PHONY: all run clean

View File

@ -4,7 +4,6 @@
#include <iostream>
#include <string>
#include <vector>
#include <windows.h>
void print(const std::string s) { std::cout << s << std::endl; }
void printErrorStringContainsNotNumber(const std::string s) {

View File

@ -63,8 +63,78 @@ bool validInput(const std::string s) {
return 1;
}
// cppcheck-suppress missingReturn
std::vector<int> requiredShoots(const int pointsLeft) {}
// Darts checkout finder: find combinations of up to 3 darts that reduce
// pointsLeft to exactly 0, finishing on a double (standard 501 rules).
std::vector<int> requiredShoots(const int pointsLeft) {
// All valid dart scores with labels
std::vector<std::pair<int, std::string>> all_darts;
for (int i = MIN_SPOT; i <= MAX_SPOT; i++)
all_darts.push_back({i, std::to_string(i)});
all_darts.push_back({25, "Bull"});
for (int i = MIN_SPOT; i <= MAX_SPOT; i++)
all_darts.push_back({i * 2, "D" + std::to_string(i)});
all_darts.push_back({50, "D-Bull"});
for (int i = MIN_SPOT; i <= MAX_SPOT; i++)
all_darts.push_back({i * 3, "T" + std::to_string(i)});
// Doubles only (valid finishing darts)
std::vector<std::pair<int, std::string>> doubles;
for (int i = MIN_SPOT; i <= MAX_SPOT; i++)
doubles.push_back({i * 2, "D" + std::to_string(i)});
doubles.push_back({50, "D-Bull"});
std::vector<std::vector<std::string>> checkouts;
const int MAX_RESULTS = 5;
// 1-dart checkouts
for (auto &d : doubles)
if (d.first == pointsLeft)
checkouts.push_back({d.second});
// 2-dart checkouts
for (auto &d1 : all_darts) {
for (auto &d2 : doubles) {
if (d1.first + d2.first == pointsLeft) {
checkouts.push_back({d1.second, d2.second});
if ((int)checkouts.size() >= MAX_RESULTS)
goto done;
}
}
}
// 3-dart checkouts (stop early once we have enough results)
for (auto &d1 : all_darts) {
for (auto &d2 : all_darts) {
for (auto &d3 : doubles) {
if (d1.first + d2.first + d3.first == pointsLeft) {
checkouts.push_back({d1.second, d2.second, d3.second});
if ((int)checkouts.size() >= MAX_RESULTS)
goto done;
}
}
}
}
done:
if (checkouts.empty()) {
print("No checkout possible for " + std::to_string(pointsLeft) +
" points.");
return {};
}
print("Possible checkouts (showing up to " + std::to_string(MAX_RESULTS) +
"):");
std::vector<int> firstCheckout;
for (auto &combo : checkouts) {
std::string line;
for (unsigned int i = 0; i < combo.size(); i++) {
if (i > 0)
line += " \u2192 ";
line += combo[i];
}
print(line);
}
return firstCheckout;
}
int main() {
print("Enter points left: ");

View File

@ -0,0 +1,4 @@
#!/usr/bin/env bash
set -e
make
./darts

View File

@ -0,0 +1,19 @@
CXX := g++
CXXFLAGS := -O2 -Wall -Wextra -std=c++17
LDFLAGS :=
SRC := main.cpp
BIN := find_percentage
all: $(BIN)
$(BIN): $(SRC)
$(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS)
run: $(BIN)
./$(BIN)
clean:
rm -f $(BIN)
.PHONY: all run clean

View File

@ -0,0 +1,4 @@
#!/usr/bin/env bash
set -e
make
./find_percentage

View File

@ -0,0 +1,19 @@
CXX := g++
CXXFLAGS := -O2 -Wall -Wextra -std=c++17
LDFLAGS :=
SRC := 11.cpp
BIN := isbn_counter
all: $(BIN)
$(BIN): $(SRC)
$(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS)
run: $(BIN)
./$(BIN)
clean:
rm -f $(BIN)
.PHONY: all run clean

View File

@ -0,0 +1,4 @@
#!/usr/bin/env bash
set -e
make
./isbn_counter

View File

@ -0,0 +1,20 @@
CXX := g++
CXXFLAGS := -O2 -Wall -Wextra -std=c++17
LDFLAGS :=
# main.cpp includes basic.cpp directly
SRC := main.cpp
BIN := markov
all: $(BIN)
$(BIN): $(SRC)
$(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS)
run: $(BIN)
./$(BIN)
clean:
rm -f $(BIN)
.PHONY: all run clean

View File

@ -9,21 +9,20 @@
struct wordOccurences {
std::string word;
int occurences;
}
};
struct previousWords {
std::string word;
std::vector<wordOccurences> previousWords;
};
struct wordProbabiliy {
struct wordProbability {
std::string previousWord;
std::string nextWord;
float probability;
}
};
bool validInput(const std::string userInput)
{
bool validInput(const std::string userInput) {
if (stringContainsNumbers(userInput))
return 0;
return 1;
@ -61,8 +60,10 @@ int wordRepeats(const std::vector<previousWords> wordsList,
bool alreadyExists(const std::vector<previousWords> wordsList,
const std::string s) {
for (unsigned int i = 0; i < wordsList.size(); i++) {
if(s == wordsList.previousWOrds
if (s == wordsList.at(i).word)
return true;
}
return false;
}
std::vector<previousWords>
@ -73,7 +74,7 @@ getWordsAndTheirPrevious(const std::vector<std::string> words) {
previousWords temp;
temp.word = words.at(i);
wordOccurences tempTwo;
tempTwo.word = words.at(i - 1));
tempTwo.word = words.at(i - 1);
tempTwo.occurences = 1;
temp.previousWords.push_back(tempTwo);
int position = wordRepeats(wordsList, temp.word);
@ -81,8 +82,7 @@ getWordsAndTheirPrevious(const std::vector<std::string> words) {
wordsList.push_back(temp);
} else {
wordsList.at(position).previousWords.push_back(
temp.previousWords.at(0));
wordsList.at(position).previousWords.push_back(temp.previousWords.at(0));
}
}
return wordsList;
@ -92,7 +92,7 @@ void printPreviousWord(const previousWords word) {
std::cout << "The word is \"" << word.word
<< "\" Words before it are: " << std::endl;
for (unsigned int i = 0; i < word.previousWords.size(); i++) {
print(word.previousWords.at(i));
print(word.previousWords.at(i).word);
}
}
@ -105,10 +105,23 @@ void printPreviousWordsVector(const std::vector<previousWords> v) {
std::vector<wordProbability>
getWordProbability(const std::vector<previousWords> wordsList) {
std::vector<wordProbability> probalityVector;
for (unsigned int i = 0; i - 1 < wordsList.size(); i++) {
pro
for (unsigned int i = 0; i < wordsList.size(); i++) {
int total = 0;
for (unsigned int j = 0; j < wordsList.at(i).previousWords.size(); j++)
total += wordsList.at(i).previousWords.at(j).occurences;
for (unsigned int j = 0; j < wordsList.at(i).previousWords.size(); j++) {
wordProbability wp;
wp.previousWord = wordsList.at(i).previousWords.at(j).word;
wp.nextWord = wordsList.at(i).word;
wp.probability =
total > 0
? (float)wordsList.at(i).previousWords.at(j).occurences / total
: 0.0f;
probalityVector.push_back(wp);
}
}
return probalityVector;
}
int main() {
std::string userInput;

View File

@ -0,0 +1,4 @@
#!/usr/bin/env bash
set -e
make
./markov

View File

@ -0,0 +1,19 @@
CXX := g++
CXXFLAGS := -O2 -Wall -Wextra -std=c++17
LDFLAGS :=
SRC := multiplication.cpp
BIN := multiplication
all: $(BIN)
$(BIN): $(SRC)
$(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS)
run: $(BIN)
./$(BIN)
clean:
rm -f $(BIN)
.PHONY: all run clean

View File

@ -0,0 +1,4 @@
#!/usr/bin/env bash
set -e
make
./multiplication

View File

@ -0,0 +1,19 @@
CXX := g++
CXXFLAGS := -O2 -Wall -Wextra -std=c++17
LDFLAGS :=
SRC := main.cpp
BIN := random_device_demo
all: $(BIN)
$(BIN): $(SRC)
$(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS)
run: $(BIN)
./$(BIN)
clean:
rm -f $(BIN)
.PHONY: all run clean

View File

@ -0,0 +1,4 @@
#!/usr/bin/env bash
set -e
make
./random_device_demo

7
CPP/miscelanious/run.sh Executable file
View File

@ -0,0 +1,7 @@
#!/usr/bin/env bash
set -e
make
./howOftenDoesCharOccur
./quickchallenges
./reverseString
./solveQuadraticEquation

View File

@ -0,0 +1,19 @@
CXX := g++
CXXFLAGS := -O2 -Wall -Wextra -std=c++17
LDFLAGS :=
SRC := tictactoe.cpp
BIN := tictactoe
all: $(BIN)
$(BIN): $(SRC)
$(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS)
run: $(BIN)
./$(BIN)
clean:
rm -f $(BIN)
.PHONY: all run clean

View File

@ -0,0 +1,4 @@
#!/usr/bin/env bash
set -e
make
./tictactoe

View File

@ -0,0 +1,19 @@
CXX := g++
CXXFLAGS := -O2 -Wall -Wextra -std=c++17
LDFLAGS :=
SRC := tierListConverter.cpp
BIN := tier_list_converter
all: $(BIN)
$(BIN): $(SRC)
$(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS)
run: $(BIN)
./$(BIN)
clean:
rm -f $(BIN)
.PHONY: all run clean

View File

@ -0,0 +1,4 @@
#!/usr/bin/env bash
set -e
make
./tier_list_converter

View File

@ -0,0 +1,19 @@
CXX := g++
CXXFLAGS := -O2 -Wall -Wextra -std=c++17
LDFLAGS :=
SRC := xgoes.cpp
BIN := xgoes
all: $(BIN)
$(BIN): $(SRC)
$(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS)
run: $(BIN)
./$(BIN)
clean:
rm -f $(BIN)
.PHONY: all run clean

View File

@ -0,0 +1,4 @@
#!/usr/bin/env bash
set -e
make
./xgoes

View File

@ -0,0 +1,22 @@
CXX := g++
CXXFLAGS := -O2 -Wall -Wextra -std=c++17
LDFLAGS :=
BINS := bernouli test
all: $(BINS)
bernouli: bernouli.cpp
$(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS)
test: test.cpp
$(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS)
run: all
./bernouli
./test
clean:
rm -f $(BINS)
.PHONY: all run clean

View File

@ -0,0 +1,5 @@
#!/usr/bin/env bash
set -e
make
./bernouli
./test

View File

@ -0,0 +1,4 @@
#!/usr/bin/env bash
set -e
make
./a.out

19
CPP/tests/Makefile Normal file
View File

@ -0,0 +1,19 @@
CXX := g++
CXXFLAGS := -O2 -Wall -Wextra -std=c++17
LDFLAGS :=
SRC := howCppHandlesDivision.cpp
BIN := division_test
all: $(BIN)
$(BIN): $(SRC)
$(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS)
run: $(BIN)
./$(BIN)
clean:
rm -f $(BIN)
.PHONY: all run clean

4
CPP/tests/run.sh Executable file
View File

@ -0,0 +1,4 @@
#!/usr/bin/env bash
set -e
make
./division_test

View File

@ -21,8 +21,7 @@ echo "Activating virtual environment..."
source "$VENV_DIR/bin/activate"
echo "Installing dependencies..."
pip install --quiet --upgrade pip
pip install --quiet matplotlib genanki geopandas requests shapely
pip show genanki &>/dev/null || pip install --quiet matplotlib genanki geopandas requests shapely
cd "$SCRIPT_DIR"

View File

@ -0,0 +1,9 @@
#!/usr/bin/env bash
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
VENV="$REPO_ROOT/.venv"
[[ ! -d "$VENV" ]] && python3 -m venv "$VENV"
_pip_sync() { local r="$1" h; h=$(md5sum "$r"|cut -d' ' -f1); local lf="$VENV/.req_${h:0:8}.lock"; [[ -f "$lf" ]] && return; "$VENV/bin/pip" install -r "$r" -q && touch "$lf"; }
_pip_sync "$REPO_ROOT/requirements.txt"
"$VENV/bin/python" "$SCRIPT_DIR/polish_license_plates_anki.py" "$@"

View File

@ -19,8 +19,7 @@ echo "Activating virtual environment..."
source "$VENV_DIR/bin/activate"
echo "Installing dependencies..."
pip install --quiet --upgrade pip
pip install --quiet matplotlib genanki geopandas
pip show genanki &>/dev/null || pip install --quiet matplotlib genanki geopandas
cd "$SCRIPT_DIR"

16
python_pkg/anki_decks/run.sh Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env bash
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
VENV="$REPO_ROOT/.venv"
[[ ! -d "$VENV" ]] && python3 -m venv "$VENV"
_pip_sync() { local r="$1" h; h=$(md5sum "$r"|cut -d' ' -f1); local lf="$VENV/.req_${h:0:8}.lock"; [[ -f "$lf" ]] && return; "$VENV/bin/pip" install -r "$r" -q && touch "$lf"; }
_pip_sync "$REPO_ROOT/requirements.txt"
# Run all deck generators in sequence
for deck_dir in "$SCRIPT_DIR"/*/; do
if [[ -f "$deck_dir/run.sh" ]]; then
echo "==> Building deck: $(basename "$deck_dir")"
bash "$deck_dir/run.sh"
fi
done

View File

@ -19,8 +19,7 @@ echo "Activating virtual environment..."
source "$VENV_DIR/bin/activate"
echo "Installing dependencies..."
pip install --quiet --upgrade pip
pip install --quiet matplotlib genanki geopandas requests shapely
pip show genanki &>/dev/null || pip install --quiet matplotlib genanki geopandas requests shapely
cd "$SCRIPT_DIR"

View File

@ -22,8 +22,7 @@ source "$VENV_DIR/bin/activate"
# Install dependencies
echo "Installing dependencies..."
pip install --quiet --upgrade pip
pip install --quiet matplotlib genanki geopandas
pip show genanki &>/dev/null || pip install --quiet matplotlib genanki geopandas
# Export preview images
echo

View File

@ -19,8 +19,7 @@ echo "Activating virtual environment..."
source "$VENV_DIR/bin/activate"
echo "Installing dependencies..."
pip install --quiet --upgrade pip
pip install --quiet matplotlib genanki geopandas requests shapely
pip show genanki &>/dev/null || pip install --quiet matplotlib genanki geopandas requests shapely
cd "$SCRIPT_DIR"

View File

@ -19,8 +19,7 @@ echo "Activating virtual environment..."
source "$VENV_DIR/bin/activate"
echo "Installing dependencies..."
pip install --quiet --upgrade pip
pip install --quiet matplotlib genanki geopandas requests shapely
pip show genanki &>/dev/null || pip install --quiet matplotlib genanki geopandas requests shapely
cd "$SCRIPT_DIR"

View File

@ -19,8 +19,7 @@ echo "Activating virtual environment..."
source "$VENV_DIR/bin/activate"
echo "Installing dependencies..."
pip install --quiet --upgrade pip
pip install --quiet matplotlib genanki geopandas requests shapely
pip show genanki &>/dev/null || pip install --quiet matplotlib genanki geopandas requests shapely
cd "$SCRIPT_DIR"

View File

@ -19,8 +19,7 @@ echo "Activating virtual environment..."
source "$VENV_DIR/bin/activate"
echo "Installing dependencies..."
pip install --quiet --upgrade pip
pip install --quiet matplotlib genanki geopandas requests shapely
pip show genanki &>/dev/null || pip install --quiet matplotlib genanki geopandas requests shapely
cd "$SCRIPT_DIR"

View File

@ -0,0 +1,9 @@
#!/usr/bin/env bash
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
VENV="$REPO_ROOT/.venv"
[[ ! -d "$VENV" ]] && python3 -m venv "$VENV"
_pip_sync() { local r="$1" h; h=$(md5sum "$r"|cut -d' ' -f1); local lf="$VENV/.req_${h:0:8}.lock"; [[ -f "$lf" ]] && return; "$VENV/bin/pip" install -r "$r" -q && touch "$lf"; }
_pip_sync "$REPO_ROOT/requirements.txt"
"$VENV/bin/python" "$SCRIPT_DIR/brightness_controller.py" "$@"

View File

@ -1,4 +1 @@
json
os
pathlib
requests

View File

@ -0,0 +1,9 @@
#!/usr/bin/env bash
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
VENV="$REPO_ROOT/.venv"
[[ ! -d "$VENV" ]] && python3 -m venv "$VENV"
_pip_sync() { local r="$1" h; h=$(md5sum "$r"|cut -d' ' -f1); local lf="$VENV/.req_${h:0:8}.lock"; [[ -f "$lf" ]] && return; "$VENV/bin/pip" install -r "$r" -q && touch "$lf"; }
_pip_sync "$SCRIPT_DIR/requirements.txt"
"$VENV/bin/python" "$SCRIPT_DIR/generate_cats.py" "$@"

11
python_pkg/keyboard_coop/run.sh Executable file
View File

@ -0,0 +1,11 @@
#!/usr/bin/env bash
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# pygame has no prebuilt wheel for Python 3.14+, use the system package
pacman -Q python-pygame &>/dev/null || sudo pacman -S --noconfirm python-pygame
# Use a local venv with --system-site-packages so it can see system pygame
VENV="$SCRIPT_DIR/.venv"
[[ ! -d "$VENV" ]] && python3 -m venv "$VENV" --system-site-packages
"$VENV/bin/python" "$SCRIPT_DIR/main.py" "$@"

View File

@ -67,4 +67,4 @@ echo "Starting Lichess bot..."
echo "Tip: Open another terminal to watch logs; press Ctrl+C here to stop."
trap 'echo; echo "Stopping bot (Ctrl+C)."' INT
"$PY" -m PYTHON.lichess_bot.main "$@"
"$PY" -m python_pkg.lichess_bot.main "$@"

View File

@ -1,2 +1,17 @@
#!/bin/sh
mitmdump -s mock_server.py
#!/usr/bin/env bash
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Use a local venv with pip-installed mitmproxy (not in Arch repos)
LVENV="$SCRIPT_DIR/.venv"
if [[ ! -d "$LVENV" ]]; then
echo "Creating local venv for mitmproxy..."
python3 -m venv "$LVENV"
fi
if ! "$LVENV/bin/python" -c "import mitmproxy" &>/dev/null; then
echo "Installing mitmproxy..."
"$LVENV/bin/pip" install mitmproxy -q
fi
cd "$SCRIPT_DIR"
"$LVENV/bin/mitmdump" --scripts mock_server.py "$@"

10
python_pkg/music_gen/run.sh Executable file
View File

@ -0,0 +1,10 @@
#!/usr/bin/env bash
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
VENV="$REPO_ROOT/.venv"
[[ ! -d "$VENV" ]] && python3 -m venv "$VENV"
"$VENV/bin/pip" show torch &>/dev/null || "$VENV/bin/pip" install torch transformers numpy scipy bark -q
echo "Loading models (this may take a minute on first run)..."
export PYTHONUNBUFFERED=1
"$VENV/bin/python" "$SCRIPT_DIR/music_generator.py" "$@"

View File

@ -0,0 +1,16 @@
#!/usr/bin/env bash
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
VENV="$REPO_ROOT/.venv"
[[ ! -d "$VENV" ]] && python3 -m venv "$VENV"
"$VENV/bin/pip" show moviepy &>/dev/null || "$VENV/bin/pip" install moviepy numpy -q
export PYTHONUNBUFFERED=1
# Run all visualizations
echo "==> Rendering visualize_q02 (Dijkstra/Bellman-Ford/A*)"
"$VENV/bin/python" "$SCRIPT_DIR/visualize_q02.py" "$@"
echo "==> Rendering visualize_q23"
"$VENV/bin/python" "$SCRIPT_DIR/visualize_q23.py" "$@"
echo "==> Rendering visualize_q24"
"$VENV/bin/python" "$SCRIPT_DIR/visualize_q24.py" "$@"
echo "Done."

View File

@ -0,0 +1,4 @@
#!/usr/bin/env bash
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
"$SCRIPT_DIR/../../.venv/bin/python" "$SCRIPT_DIR/random_digits.py" "$@"

View File

@ -0,0 +1,594 @@
#!/usr/bin/env python3
"""Repo Explorer - browse and run any project in the monorepo via a GUI."""
from __future__ import annotations
import contextlib
import fcntl
import os
from pathlib import Path
import pty
import re
import select
import shutil
import subprocess
import threading
import tkinter as tk
from tkinter import font, ttk
from typing import cast
# Strip ANSI/VT100 escape sequences so the Text widget shows plain text
_ANSI_ESCAPE = re.compile(r"\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])")
def _strip_ansi(text: str) -> str:
return _ANSI_ESCAPE.sub("", text)
def _find_terminal() -> list[str]:
"""Return argv prefix for the first available terminal emulator."""
candidates = [
("kitty", ["kitty", "--"]),
("alacritty", ["alacritty", "-e"]),
("konsole", ["konsole", "-e"]),
("gnome-terminal", ["gnome-terminal", "--"]),
("xfce4-terminal", ["xfce4-terminal", "-x"]),
("xterm", ["xterm", "-e"]),
]
for exe, args in candidates:
if shutil.which(exe):
return args
return []
REPO_ROOT = Path(__file__).resolve().parent.parent.parent
IGNORED_DIRS = {
".git",
".venv",
"__pycache__",
"node_modules",
"build",
"target",
".mypy_cache",
".ruff_cache",
}
# ---------------------------------------------------------------------------
# Discovery helpers
# ---------------------------------------------------------------------------
def _is_ignored(path: Path) -> bool:
return any(part in IGNORED_DIRS for part in path.parts)
def find_projects(root: Path) -> list[dict[str, object]]:
"""Return every directory under *root* that contains a run.sh."""
projects: list[dict[str, object]] = []
for run_sh in sorted(root.rglob("run.sh")):
if _is_ignored(run_sh):
continue
proj_dir = run_sh.parent
rel = proj_dir.relative_to(root)
projects.append({"path": proj_dir, "rel": rel, "name": proj_dir.name})
return projects
def _desc_from_run_sh(run_sh: Path) -> str:
"""Extract leading comment block from run.sh as a description."""
comments: list[str] = []
for line in run_sh.read_text(errors="replace").splitlines():
s = line.strip()
if s.startswith("#!"):
continue
if s.startswith("#"):
comments.append(s[1:].strip())
elif comments:
break
return " ".join(comments)[:300] if comments else ""
def get_description(project_path: Path) -> str:
"""Return a short description from README.md or leading run.sh comments."""
for readme_name in ("README.md", "README.txt", "readme.md"):
readme = project_path / readme_name
if readme.exists():
text = readme.read_text(errors="replace")
for line in text.splitlines():
stripped = line.strip().lstrip("#").strip()
if stripped:
return stripped[:300]
run_sh = project_path / "run.sh"
if run_sh.exists():
desc = _desc_from_run_sh(run_sh)
if desc:
return desc
return "(no description)"
# ---------------------------------------------------------------------------
# Main application
# ---------------------------------------------------------------------------
class RepoExplorer(tk.Tk):
"""Main application window for browsing and running monorepo projects."""
# Catppuccin Mocha palette
_BG = "#1e1e2e"
_SURFACE = "#313244"
_TEXT = "#cdd6f4"
_TEXT_DIM = "#6c7086"
_ACCENT = "#89b4fa"
_GREEN = "#a6e3a1"
_RED = "#f38ba8"
_TERMINAL_BG = "#11111b"
_MAX_EXPAND = 60 # expand tree groups automatically when <= this many results
_IDLE_FLUSH_TICKS = 2 # flush partial PTY buffer after this many 50 ms timeouts
def __init__(self) -> None:
"""Initialise the window, build the UI and load all projects."""
super().__init__()
self.title("Repo Explorer")
self.geometry("1200x750")
self.configure(bg=self._BG)
self._proc: subprocess.Popen[bytes] | None = None
self._master_fd: int | None = None
self._projects: list[dict[str, object]] = []
self._terminal_args = _find_terminal()
self._build_style()
self._build_ui()
self._load_projects()
# ------------------------------------------------------------------
# UI construction
# ------------------------------------------------------------------
def _build_style(self) -> None:
s = ttk.Style(self)
s.theme_use("clam")
opts: dict[str, object]
opts = {
"background": self._BG,
"foreground": self._TEXT,
"fieldbackground": self._BG,
"font": ("Monospace", 10),
"rowheight": 24,
}
s.configure("Treeview", **opts)
s.configure(
"Treeview.Heading", background=self._SURFACE, foreground=self._ACCENT
)
s.map(
"Treeview",
background=[("selected", self._SURFACE)],
foreground=[("selected", self._ACCENT)],
)
s.configure("TFrame", background=self._BG)
s.configure("TLabel", background=self._BG, foreground=self._TEXT)
s.configure(
"TButton", background=self._SURFACE, foreground=self._TEXT, padding=4
)
s.map(
"TButton",
background=[("active", "#45475a"), ("disabled", self._BG)],
foreground=[("disabled", self._TEXT_DIM)],
)
s.configure(
"TEntry",
fieldbackground=self._SURFACE,
foreground=self._TEXT,
insertcolor=self._TEXT,
)
s.configure("TPanedwindow", background=self._BG)
s.configure("TSeparator", background=self._SURFACE)
def _build_ui(self) -> None:
paned = ttk.PanedWindow(self, orient=tk.HORIZONTAL)
paned.pack(fill=tk.BOTH, expand=True, padx=6, pady=6)
paned.add(self._build_left(paned), weight=1)
paned.add(self._build_right(paned), weight=3)
def _build_left(self, parent: ttk.PanedWindow) -> ttk.Frame:
frame = ttk.Frame(parent)
# Search bar
sf = ttk.Frame(frame)
sf.pack(fill=tk.X, padx=4, pady=(4, 2))
ttk.Label(sf, text="Search:").pack(side=tk.LEFT)
self._search_var = tk.StringVar()
self._search_var.trace_add("write", lambda *_: self._filter_tree())
ttk.Entry(sf, textvariable=self._search_var).pack(
side=tk.LEFT, fill=tk.X, expand=True, padx=(4, 0)
)
# Project count label
self._count_var = tk.StringVar(value="")
ttk.Label(
frame,
textvariable=self._count_var,
foreground=self._TEXT_DIM,
font=("sans-serif", 8),
).pack(anchor=tk.W, padx=6)
# Tree + scrollbar
tree_frame = ttk.Frame(frame)
tree_frame.pack(fill=tk.BOTH, expand=True, padx=4, pady=4)
self._tree = ttk.Treeview(tree_frame, show="tree", selectmode="browse")
scroll = ttk.Scrollbar(tree_frame, command=self._tree.yview)
self._tree.configure(yscrollcommand=scroll.set)
scroll.pack(side=tk.RIGHT, fill=tk.Y)
self._tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
self._tree.bind("<<TreeviewSelect>>", self._on_select)
self._tree.bind("<Double-1>", lambda _: self._run_embedded())
self._tree.bind("<Return>", lambda _: self._run_embedded())
return frame
def _build_right(self, parent: ttk.PanedWindow) -> ttk.Frame:
frame = ttk.Frame(parent)
# Description section
info_frame = ttk.Frame(frame)
info_frame.pack(fill=tk.X, padx=6, pady=(4, 0))
ttk.Label(
info_frame,
text="Project",
font=("sans-serif", 11, "bold"),
foreground=self._ACCENT,
).pack(anchor=tk.W)
self._title_var = tk.StringVar(value="Select a project from the list")
ttk.Label(
info_frame,
textvariable=self._title_var,
font=("Monospace", 9),
foreground=self._TEXT_DIM,
).pack(anchor=tk.W)
self._desc_var = tk.StringVar(value="")
ttk.Label(
info_frame,
textvariable=self._desc_var,
wraplength=700,
justify=tk.LEFT,
foreground=self._GREEN,
).pack(anchor=tk.W, pady=(2, 0))
ttk.Separator(frame, orient=tk.HORIZONTAL).pack(fill=tk.X, padx=6, pady=4)
# Args + buttons row
ctrl_frame = ttk.Frame(frame)
ctrl_frame.pack(fill=tk.X, padx=6, pady=(0, 4))
ttk.Label(ctrl_frame, text="Args:").pack(side=tk.LEFT)
self._args_var = tk.StringVar()
ttk.Entry(ctrl_frame, textvariable=self._args_var, width=30).pack(
side=tk.LEFT, padx=(4, 12)
)
self._run_btn = ttk.Button(
ctrl_frame,
text="▶ Run here",
command=self._run_embedded,
state=tk.DISABLED,
)
self._run_btn.pack(side=tk.LEFT, padx=(0, 4))
term_label = self._terminal_args[0] if self._terminal_args else "terminal"
self._term_btn = ttk.Button(
ctrl_frame,
text=f"⧉ Open in {term_label}",
command=self._run_in_terminal,
state=tk.DISABLED,
)
self._term_btn.pack(side=tk.LEFT, padx=(0, 4))
self._stop_btn = ttk.Button(
ctrl_frame, text="■ Stop", command=self._stop, state=tk.DISABLED
)
self._stop_btn.pack(side=tk.LEFT, padx=(0, 4))
ttk.Button(ctrl_frame, text="✕ Clear", command=self._clear).pack(side=tk.LEFT)
# Status indicator
self._status_var = tk.StringVar(value="")
ttk.Label(
ctrl_frame, textvariable=self._status_var, font=("sans-serif", 9)
).pack(side=tk.RIGHT)
# stdin input row (for interactive embedded processes)
stdin_frame = ttk.Frame(frame)
stdin_frame.pack(fill=tk.X, padx=6, pady=(0, 4))
ttk.Label(stdin_frame, text="Send input:").pack(side=tk.LEFT)
self._stdin_var = tk.StringVar()
stdin_entry = ttk.Entry(stdin_frame, textvariable=self._stdin_var)
stdin_entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=(4, 4))
stdin_entry.bind("<Return>", self._send_stdin)
ttk.Button(stdin_frame, text="↵ Send", command=self._send_stdin).pack(
side=tk.LEFT
)
# Output terminal
term_frame = ttk.Frame(frame)
term_frame.pack(fill=tk.BOTH, expand=True, padx=6, pady=(0, 6))
mono = font.Font(family="Monospace", size=9)
self._output = tk.Text(
term_frame,
bg=self._TERMINAL_BG,
fg=self._TEXT,
font=mono,
wrap=tk.WORD,
state=tk.DISABLED,
relief=tk.FLAT,
insertbackground=self._TEXT,
)
out_scroll = ttk.Scrollbar(term_frame, command=self._output.yview)
self._output.configure(yscrollcommand=out_scroll.set)
out_scroll.pack(side=tk.RIGHT, fill=tk.Y)
self._output.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
self._output.tag_config("stderr", foreground=self._RED)
self._output.tag_config("info", foreground=self._ACCENT)
self._output.tag_config("success", foreground=self._GREEN)
self._output.tag_config("error", foreground=self._RED)
return frame
# ------------------------------------------------------------------
# Project discovery / tree population
# ------------------------------------------------------------------
def _load_projects(self) -> None:
self._projects = find_projects(REPO_ROOT)
self._populate_tree(self._projects)
def _populate_tree(self, projects: list[dict[str, object]]) -> None:
self._tree.delete(*self._tree.get_children())
groups: dict[str, list[dict[str, object]]] = {}
for p in projects:
rel = cast("Path", p["rel"])
parts = rel.parts
group = parts[0] if len(parts) > 1 else "(root)"
groups.setdefault(group, []).append(p)
icons = {
"python_pkg": "🐍",
"C": "⚙️",
"CPP": "⚙️",
"articles": "📰",
"TS": "📜",
"Bash": "🐚",
}
for group, items in sorted(groups.items()):
icon = icons.get(group, "📁")
gid = self._tree.insert("", tk.END, text=f"{icon} {group}", tags=("group",))
for item in items:
rel2 = cast("Path", item["rel"])
label = cast(
"str",
"/".join(rel2.parts[1:]) if len(rel2.parts) > 1 else item["name"],
)
path_str = str(item["path"])
self._tree.insert(gid, tk.END, text=f" {label}", values=[path_str])
self._tree.tag_configure("group", foreground=self._TEXT_DIM)
# Expand all groups if result set is small enough
if len(projects) <= self._MAX_EXPAND:
for gid in self._tree.get_children():
self._tree.item(gid, open=True)
n = len(projects)
self._count_var.set(f"{n} project{'s' if n != 1 else ''}")
def _filter_tree(self) -> None:
q = self._search_var.get().lower()
if not q:
self._populate_tree(self._projects)
return
filtered = [
p
for p in self._projects
if q in str(p["rel"]).lower() or q in str(p["name"]).lower()
]
self._populate_tree(filtered)
# ------------------------------------------------------------------
# Selection / info panel
# ------------------------------------------------------------------
def _selected_path(self) -> Path | None:
sel = self._tree.selection()
if not sel:
return None
vals = self._tree.item(sel[0], "values")
if not vals:
return None
return Path(vals[0])
def _on_select(self, _event: object) -> None:
path = self._selected_path()
if path is None:
self._run_btn.configure(state=tk.DISABLED)
self._term_btn.configure(state=tk.DISABLED)
return
self._title_var.set(str(path.relative_to(REPO_ROOT)))
self._desc_var.set(get_description(path))
self._run_btn.configure(state=tk.NORMAL)
self._term_btn.configure(
state=tk.NORMAL if self._terminal_args else tk.DISABLED
)
# ------------------------------------------------------------------
# Run in external terminal (for interactive / keyboard-driven programs)
# ------------------------------------------------------------------
def _run_in_terminal(self) -> None:
path = self._selected_path()
if path is None or not self._terminal_args:
return
args_str = self._args_var.get().strip()
extra = args_str.split() if args_str else []
subprocess.Popen([*self._terminal_args, "bash", "run.sh", *extra], cwd=path)
self._write_output(
f"$ Launched in {self._terminal_args[0]}: {path.relative_to(REPO_ROOT)}\n",
"info",
)
# ------------------------------------------------------------------
# Run embedded with PTY (captures terminal-aware / ncurses output)
# ------------------------------------------------------------------
def _run_embedded(self) -> None:
path = self._selected_path()
if path is None:
return
if self._proc and self._proc.poll() is None:
self._stop()
self._clear()
args_str = self._args_var.get().strip()
extra = args_str.split() if args_str else []
display_cmd = ("bash run.sh " + args_str).strip()
self._write_output(
f"$ {display_cmd} [{path.relative_to(REPO_ROOT)}]\n", "info"
)
master_fd, slave_fd = pty.openpty()
self._master_fd = master_fd
# Non-blocking reads on master so the reader thread doesn't stall
fl = fcntl.fcntl(master_fd, fcntl.F_GETFL)
fcntl.fcntl(master_fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
self._proc = subprocess.Popen(
["bash", "run.sh", *extra], # noqa: S607
cwd=path,
stdin=slave_fd,
stdout=slave_fd,
stderr=slave_fd,
close_fds=True,
)
os.close(slave_fd)
self._run_btn.configure(state=tk.DISABLED)
self._stop_btn.configure(state=tk.NORMAL)
self._status_var.set("● running")
threading.Thread(target=self._read_pty, daemon=True).start()
threading.Thread(target=self._wait_proc, daemon=True).start()
def _read_pty(self) -> None: # noqa: C901, PLR0912
"""Stream PTY output to the widget, stripping ANSI codes.
Partial lines (prompts without a trailing newline) are flushed after
~100 ms of silence so interactive prompts like "Enter value: " appear.
"""
buf = b""
idle_ticks = 0 # consecutive 50 ms timeouts while buf has content
while self._proc and self._proc.poll() is None:
mfd = self._master_fd
if mfd is None:
break
ready, _, _ = select.select([mfd], [], [], 0.05)
if not ready:
# No new data — flush partial buffer after ~100 ms (2 ticks)
if buf:
idle_ticks += 1
if idle_ticks >= self._IDLE_FLUSH_TICKS:
text = _strip_ansi(
buf.decode("utf-8", errors="replace").replace("\r", "")
)
if text:
self._write_output(text)
buf = b""
idle_ticks = 0
continue
idle_ticks = 0
try:
chunk = os.read(mfd, 4096)
except OSError:
break
if not chunk:
break
buf += chunk
while b"\n" in buf:
line, buf = buf.split(b"\n", 1)
text = _strip_ansi(
line.decode("utf-8", errors="replace").replace("\r", "")
)
if text:
self._write_output(text + "\n")
# flush remainder
if buf:
text = _strip_ansi(buf.decode("utf-8", errors="replace").replace("\r", ""))
if text:
self._write_output(text)
if self._master_fd is not None:
with contextlib.suppress(OSError):
os.close(self._master_fd)
self._master_fd = None
# ------------------------------------------------------------------
# stdin forwarding (typed into the "Send input" field)
# ------------------------------------------------------------------
def _send_stdin(self, _event: object = None) -> None:
text = self._stdin_var.get()
self._stdin_var.set("")
payload = (text + "\n").encode()
if self._master_fd is not None:
with contextlib.suppress(OSError):
os.write(self._master_fd, payload)
def _wait_proc(self) -> None:
if self._proc:
code = self._proc.wait()
self.after(0, self._on_proc_done, code)
def _on_proc_done(self, code: int) -> None:
if code == 0:
self._write_output(f"\n[exited with code {code}]\n", "success")
self._status_var.set("✓ done")
else:
self._write_output(f"\n[exited with code {code}]\n", "error")
self._status_var.set(f"✗ exit {code}")
self._run_btn.configure(state=tk.NORMAL)
self._stop_btn.configure(state=tk.DISABLED)
def _stop(self) -> None:
if self._proc and self._proc.poll() is None:
self._proc.terminate()
self._status_var.set("stopped")
def _clear(self) -> None:
self._output.configure(state=tk.NORMAL)
self._output.delete("1.0", tk.END)
self._output.configure(state=tk.DISABLED)
self._status_var.set("")
def _write_output(self, text: str, tag: str | None = None) -> None:
"""Thread-safe output append via after()."""
self.after(0, self._append_output, text, tag)
def _append_output(self, text: str, tag: str | None) -> None:
self._output.configure(state=tk.NORMAL)
if tag:
self._output.insert(tk.END, text, tag)
else:
self._output.insert(tk.END, text)
self._output.see(tk.END)
self._output.configure(state=tk.DISABLED)
# ---------------------------------------------------------------------------
if __name__ == "__main__":
RepoExplorer().mainloop()

18
python_pkg/repo_explorer/run.sh Executable file
View File

@ -0,0 +1,18 @@
#!/usr/bin/env bash
# Repo Explorer - browse and run any project in the monorepo via a GUI.
# Requires tkinter (Arch: sudo pacman -S python-tkinter)
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
VENV="$REPO_ROOT/.venv"
# Ensure tkinter is available (it's stdlib but needs the python-tkinter OS package)
if ! python3 -c "import tkinter" 2>/dev/null; then
echo "tkinter not found. Installing python-tkinter..."
sudo pacman -S --noconfirm python-tkinter 2>/dev/null \
|| sudo apt-get install -y python3-tk 2>/dev/null \
|| { echo "Please install python-tkinter manually."; exit 1; }
fi
[[ ! -d "$VENV" ]] && python3 -m venv "$VENV"
"$VENV/bin/python" "$SCRIPT_DIR/repo_explorer.py" "$@"

View File

@ -0,0 +1,10 @@
#!/usr/bin/env bash
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
VENV="$REPO_ROOT/.venv"
[[ ! -d "$VENV" ]] && python3 -m venv "$VENV"
_pip_sync() { local r="$1" h; h=$(md5sum "$r"|cut -d' ' -f1); local lf="$VENV/.req_${h:0:8}.lock"; [[ -f "$lf" ]] && return; "$VENV/bin/pip" install -r "$r" -q && touch "$lf"; }
_pip_sync "$SCRIPT_DIR/requirements.txt"
# Usage: ./run.sh <url> [--output-dir DIR] [--max-pages N]
"$VENV/bin/python" "$SCRIPT_DIR/scrape_comics.py" "$@"

View File

@ -367,19 +367,19 @@ def _configure_hash(
def _configure_multipv(
engine: chess.engine.SimpleEngine, options: EngineOptions, requested: int
_engine: chess.engine.SimpleEngine, options: EngineOptions, requested: int
) -> int:
"""Configure MultiPV and return effective value."""
effective = max(1, int(requested))
if "MultiPV" not in options:
return effective
# MultiPV is automatically managed by python-chess and passed directly to
# engine.analyse(..., multipv=N) — do not configure() it here.
if "MultiPV" in options:
try:
max_mpv = getattr(options["MultiPV"], "max", None)
if isinstance(max_mpv, int):
effective = min(effective, max_mpv)
engine.configure({"MultiPV": int(effective)})
except (AttributeError, TypeError, ValueError):
_logger.debug("Failed to configure MultiPV option")
_logger.debug("Failed to read MultiPV max option")
return effective

View File

@ -24,8 +24,12 @@ fi
# shellcheck disable=SC1090
source "$VENV_DIR/bin/activate"
# Install dependencies quietly
pip install -r "$SCRIPT_DIR/requirements.txt" >/dev/null
# Install dependencies only if requirements.txt has changed
_REQ="$SCRIPT_DIR/requirements.txt"
_HASH=$(md5sum "$_REQ" | cut -d' ' -f1)
_LOCK="$VENV_DIR/.req_${_HASH:0:8}.lock"
[[ -f "$_LOCK" ]] || { pip install -r "$_REQ" >/dev/null && touch "$_LOCK"; }
unset _REQ _HASH _LOCK
# Default engine (can override with STOCKFISH env var)
ENGINE_BIN="${STOCKFISH:-stockfish}"

9
python_pkg/tag_divider/run.sh Executable file
View File

@ -0,0 +1,9 @@
#!/usr/bin/env bash
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
VENV="$REPO_ROOT/.venv"
[[ ! -d "$VENV" ]] && python3 -m venv "$VENV"
"$VENV/bin/pip" show opencv-python &>/dev/null || "$VENV/bin/pip" install opencv-python -q
# Usage: ./run.sh <images_dir>
"$VENV/bin/python" "$SCRIPT_DIR/tag_divider.py" "$@"

View File

@ -0,0 +1,5 @@
#!/usr/bin/env bash
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Usage: ./run.sh <text_file> [options]
"$SCRIPT_DIR/../../.venv/bin/python" "$SCRIPT_DIR/vocabulary_curve.py" "$@"