random

:-)
git clone git://git.christosmarg.xyz/random.git
Log | Files | Refs | LICENSE

commit 412eca38e2f2919ba0a11796065cf1c7ac9c0a08
Author: Christos Margiolis <christos@margiolis.net>
Date:   Wed, 28 Apr 2021 03:06:33 +0300

initial commit

Diffstat:
ALICENSE | 20++++++++++++++++++++
Abrainfuck/Makefile | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Abrainfuck/README | 16++++++++++++++++
Abrainfuck/brainfuck.1 | 25+++++++++++++++++++++++++
Abrainfuck/brainfuck.c | 76++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abrainfuck/config.mk | 30++++++++++++++++++++++++++++++
Abrainfuck/tests/hello.bf | 1+
Abrainfuck/tests/triangle.bf | 5+++++
Abytepusher/Makefile | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Abytepusher/README.md | 32++++++++++++++++++++++++++++++++
Abytepusher/bytepusher.1 | 15+++++++++++++++
Abytepusher/bytepusher.c | 136+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abytepusher/config.mk | 30++++++++++++++++++++++++++++++
Abytepusher/roms/invertloopsine.BytePusher | 0
Abytepusher/roms/munchingsquares.BytePusher | 0
Abytepusher/roms/nyan.BytePusher | 0
Abytepusher/roms/palettetest.BytePusher | 0
Abytepusher/roms/scrollinglogo.BytePusher | 0
Abytepusher/roms/sinescroller.BytePusher | 0
Afnc/Makefile | 46++++++++++++++++++++++++++++++++++++++++++++++
Afnc/fnc.1 | 28++++++++++++++++++++++++++++
Afnc/fnc.go | 80+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aminecurses/Makefile | 53+++++++++++++++++++++++++++++++++++++++++++++++++++++
Aminecurses/README.md | 47+++++++++++++++++++++++++++++++++++++++++++++++
Aminecurses/config.mk | 30++++++++++++++++++++++++++++++
Aminecurses/defs.h | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aminecurses/minecurses.6 | 39+++++++++++++++++++++++++++++++++++++++
Aminecurses/minecurses.c | 372+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amorse/dash.wav | 0
Amorse/dot.wav | 0
Amorse/morse.cpp | 96+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aother/bounce.c | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aother/mandelbrot.c | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aother/nnc.cpp | 167+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aother/snake.cpp | 184+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashitcoin/Makefile | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashitcoin/README | 18++++++++++++++++++
Ashitcoin/config.mk | 30++++++++++++++++++++++++++++++
Ashitcoin/shitcoin.c | 276+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
39 files changed, 2190 insertions(+), 0 deletions(-)

diff --git a/LICENSE b/LICENSE @@ -0,0 +1,20 @@ +MIT License + +(c) 2019-Present Christos Margiolis <christos@christosmarg.xyz> + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the “Software”), to deal in +the Software without restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the +Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/brainfuck/Makefile b/brainfuck/Makefile @@ -0,0 +1,52 @@ +# brainfuck - a brainfuck interpreter +.POSIX: + +include config.mk + +BIN = brainfuck +DIST = ${BIN}-${VERSION} +MAN1 = ${BIN}.1 + +SRC = brainfuck.c +OBJ = ${SRC:.c=.o} + +all: options ${BIN} + +options: + @echo ${BIN} build options: + @echo "CFLAGS = ${CFLAGS}" + @echo "LDFLAGS = ${LDFLAGS}" + @echo "CC = ${CC}" + +${BIN}: ${OBJ} + ${CC} ${LDFLAGS} ${OBJ} -o $@ + +.c.o: + ${CC} -c ${CFLAGS} $< + +dist: clean + ${MKDIR} ${DIST} + ${CP} -R tests/ config.mk ${MAN1} ${SRC} LICENSE Makefile README.md ${DIST} + ${TAR} ${DIST}.tar ${DIST} + ${GZIP} ${DIST}.tar + ${RM_DIR} ${DIST} + +run: + ./${BIN} + +install: all + ${MKDIR} ${DESTDIR}${BIN_DIR} ${DESTDIR}${MAN_DIR} + ${CP} ${BIN} ${BIN_DIR} + ${CP} ${MAN1} ${DESTDIR}${MAN_DIR} + sed "s/VERSION/${VERSION}/g" < ${MAN1} > ${DESTDIR}${MAN_DIR}/${MAN1} + chmod 755 ${DESTDIR}${BIN_DIR}/${BIN} + chmod 644 ${DESTDIR}${MAN_DIR}/${MAN1} + +uninstall: + ${RM} ${DESTDIR}${BIN_DIR}/${BIN} + ${RM} ${DESTDIR}${MAN_DIR}/${MAN1} + +clean: + ${RM} ${BIN} ${OBJ} ${DIST}.tar.gz + +.PHONY: all options clean dist install uninstall run diff --git a/brainfuck/README b/brainfuck/README @@ -0,0 +1,16 @@ +brainfuck - a brainfuck interpreter +========================================== +brainfuck reads input from stdin and interprets it +as Brainfuck source code. + +Usage +----- + cd path/to/brainfuck + make + ./brainfuck < src.bf + +You can install brainfuck by running: + + sudo make install clean + +The binary will be installed in usr/local/bin. diff --git a/brainfuck/brainfuck.1 b/brainfuck/brainfuck.1 @@ -0,0 +1,25 @@ +.Dd brainfuck\-VERSION +.Dt BRAINFUCK 1 +.Os +.Sh NAME +.Nm brainfuck +.Nd a simple brainfuck interpreter +.Sh SYNOPSIS +.Nm +stdin +.Sh DESCRIPTION +.Nm +reads input from stdin and interprets it +as Brainfuck source code. +.Sh EXAMPLES +To parse a Brainfuck source file +.Pp +.Dl $ brainfuck < src.bf +.Pp +Alternatively, you can pipe to +.Nm +.Pp +.Dl $ cat src.bf | brainfuck +.Pp +.Sh AUTHORS +.An Christos Margiolis Aq Mt christos@christosmarg.xyz diff --git a/brainfuck/brainfuck.c b/brainfuck/brainfuck.c @@ -0,0 +1,76 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#define BUFSIZE 50000 + +int +main(int argc, char *argv[]) +{ + size_t len = 0; + int closed, opened, pos = 0; + unsigned short *pc; + char buf[BUFSIZE], *src; + + while (read(STDIN_FILENO, &buf[len], 1) > 0) + len++; + buf[len] = '\0'; + + if ((src = malloc(len)) == NULL) { + perror("malloc"); + exit(EXIT_FAILURE); + } + strcpy(src, buf); + memset(buf, 0, len); + + for (pc = (unsigned short *)buf; pos < len; pos++) { + switch (src[pos]) { + case '>': + pc++; + break; + case '<': + pc--; + break; + case '+': + (*pc)++; + break; + case '-': + (*pc)--; + break; + case '.': + putchar(*pc); + break; + case ',': + *pc = getchar(); + break; + case '[': + if (!(*pc)) { + for (opened = 0, pos++; pos < len; pos++) { + if (src[pos] == ']' && !opened) + break; + else if (src[pos] == '[') + opened++; + else if (src[pos] == ']') + opened--; + } + } + break; + case ']': + if (*pc) { + for (closed = 0, pos--; pos >= 0; pos--) { + if (src[pos] == '[' && !closed) + break; + else if (src[pos] == ']') + closed++; + else if (src[pos] == '[') + closed--; + } + } + break; + } + } + free(src); + + return 0; +} diff --git a/brainfuck/config.mk b/brainfuck/config.mk @@ -0,0 +1,30 @@ +# brainfuck version +VERSION = 0 + +# paths +PREFIX = /usr/local +MAN_DIR = ${PREFIX}/share/man/man1 +BIN_DIR = ${PREFIX}/bin + +# includes and libs +INCS = -Iinclude +LIBS = -Llib + +# flags +CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L \ + -D_XOPEN_SOURCE=700 -DVERSION=\"${VERSION}\" +CFLAGS = -std=c99 -pedantic -Wall -Os ${INCS} ${CPPFLAGS} +LDFLAGS = ${LIBS} + +# utils +CP = cp -f +RM = rm -f +RM_DIR = rm -rf +MV = mv +MKDIR = mkdir -p +RM_DIR = rm -rf +TAR = tar -cf +GZIP = gzip + +# compiler +CC = cc diff --git a/brainfuck/tests/hello.bf b/brainfuck/tests/hello.bf @@ -0,0 +1 @@ +++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++. diff --git a/brainfuck/tests/triangle.bf b/brainfuck/tests/triangle.bf @@ -0,0 +1,5 @@ +++++++++[>+>++++<<-]>++>>+<[-[>>+<<-]+>>]>+[ + -<<<[ + ->[+[-]+>++>>>-<<]<[<]>>++++++[<<+++++>>-]+<<++.[-]<< + ]>.>+[>>]>+ +] diff --git a/bytepusher/Makefile b/bytepusher/Makefile @@ -0,0 +1,52 @@ +# bytepusher - a Bytepusher VM implementation +.POSIX: + +include config.mk + +BIN = bytepusher +DIST = ${BIN}-${VERSION} +MAN1 = ${BIN}.1 + +SRC = bytepusher.c +OBJ = ${SRC:.c=.o} + +all: options ${BIN} + +options: + @echo ${BIN} build options: + @echo "CFLAGS = ${CFLAGS}" + @echo "LDFLAGS = ${LDFLAGS}" + @echo "CC = ${CC}" + +${BIN}: ${OBJ} + ${CC} ${LDFLAGS} ${OBJ} -o $@ + +.c.o: + ${CC} -c ${CFLAGS} $< + +dist: clean + ${MKDIR} ${DIST} + ${CP} -R roms/ ${MAN1} ${SRC} config.mk LICENSE Makefile README.md ${DIST} + ${TAR} ${DIST}.tar ${DIST} + ${GZIP} ${DIST}.tar + ${RM_DIR} ${DIST} + +run: + ./${BIN} + +install: all + ${MKDIR} ${DESTDIR}${BIN_DIR} ${DESTDIR}${MAN_DIR} + ${CP} ${BIN} ${BIN_DIR} + ${CP} ${MAN1} ${DESTDIR}${MAN_DIR} + sed "s/VERSION/${VERSION}/g" < ${MAN1} > ${DESTDIR}${MAN_DIR}/${MAN1} + chmod 755 ${DESTDIR}${BIN_DIR}/${BIN} + chmod 644 ${DESTDIR}${MAN_DIR}/${MAN1} + +uninstall: + ${RM} ${DESTDIR}${BIN_DIR}/${BIN} + ${RM} ${DESTDIR}${MAN_DIR}/${MAN1} + +clean: + ${RM} ${BIN} ${OBJ} ${DIST}.tar.gz + +.PHONY: all options clean dist install uninstall run diff --git a/bytepusher/README.md b/bytepusher/README.md @@ -0,0 +1,32 @@ +# BytePusher + +A cross-platform BytePusher virtual machine implementation in C and SDL. +You can learn about it here: https://esolangs.org/wiki/BytePusher + +## Usage + +SDL needs to be installed on your machine in order to run the program. +The `roms` directory contains a few roms you can try out. +```shell +$ cd path/to/bytepusher +$ make +$ ./bytepusher [ROM] +$ make clean # optional +``` +You can install `bytepusher` by running `sudo make install clean`. +The binary will be installed in `/usr/local/bin`. + +## Screenshots + +<table> + <tr> + <td><img align="left" src="https://user-images.githubusercontent.com/54286563/91668705-55886a00-eb17-11ea-94d2-07f53ca98971.png"/></td> + <td><img align="right" src="https://user-images.githubusercontent.com/54286563/91668704-54efd380-eb17-11ea-8c75-f1a35637499c.png"/></td> + <td><img align="left" src="https://user-images.githubusercontent.com/54286563/91668706-56210080-eb17-11ea-9448-812e3e664d57.png"/></td> + </tr> + <tr> + <td><img align="left" src="https://user-images.githubusercontent.com/54286563/91668708-56b99700-eb17-11ea-9c4e-7293c32d0485.png"/></td> + <td><img align="right" src="https://user-images.githubusercontent.com/54286563/91668712-56b99700-eb17-11ea-993e-74c2e160dbd3.png"/></td> + <td><img align="right" src="https://user-images.githubusercontent.com/54286563/91668707-56210080-eb17-11ea-8728-dc42b9443a0a.png"/></td> + </tr> +</table> diff --git a/bytepusher/bytepusher.1 b/bytepusher/bytepusher.1 @@ -0,0 +1,15 @@ +.Dd bytepusher\-VERSION +.Dt BYTEPUSHER 1 +.Os +.Sh NAME +.Nm bytepusher +.Nd a Bytepusher VM implementation +.Sh SYNOPSIS +.Nm +.Op rom +.Sh DESCRIPTION +.Nm +reads a Bytepusher source file and executes it. It +uses the SDL2 library as a rendering API. +.Sh AUTHORS +.An Christos Margiolis Aq Mt christos@christosmarg.xyz diff --git a/bytepusher/bytepusher.c b/bytepusher/bytepusher.c @@ -0,0 +1,136 @@ +#include <stdlib.h> + +#include <SDL2/SDL.h> + +#ifdef _WIN_32 +typedef unsigned int u_int32_t; +typedef unsigned short u_int16_t; +typedef unsigned char u_int8_t; +#else +#include <sys/types.h> +#endif /* _WIN_32 */ + +#define RGB_CALC ((r) * 0x33 << 16 | (g) * 0x33 << 8 | (b) * 0x33) +#define RGB_POS ((r) * 36 + (g) * 6 + (b)) +#define PC_POS (pc[3] << 16 | pc[4] << 8 | pc[5]) + +static u_int32_t palette[0x100]; +static u_int8_t mem[0x1000008]; +static const u_int8_t keys[16] = { + SDLK_1, SDLK_2, SDLK_3, SDLK_4, + SDLK_q, SDLK_w, SDLK_e, SDLK_r, + SDLK_a, SDLK_s, SDLK_d, SDLK_f, + SDLK_z, SDLK_x, SDLK_c, SDLK_v +}; + +static int +evhandle(void) +{ + SDL_Event ev; + size_t i; + u_int16_t keybits; + + keybits = mem[0] << 8 | mem[1]; + while (SDL_PollEvent(&ev)) { + if (ev.type == SDL_QUIT || ev.key.keysym.sym == SDLK_ESCAPE) + return 0; + if (ev.type == SDL_KEYDOWN) + for (i = 0; i < 16; i++) + if (ev.key.keysym.sym == keys[i]) + keybits = (keybits & ~(1 << i)) | + (ev.type == SDL_KEYDOWN) << i; + } + mem[0] = keybits >> 8; + mem[1] = keybits & 0xFF; + return 1; +} + +static void +cycle(void) +{ + size_t i = 0x10000; + u_int8_t *pc; + + pc = mem + (mem[2] << 16 | mem[3] << 8 | mem[4]); + while (i--) { + mem[PC_POS] = mem[pc[0] << 16 | pc[1] << 8 | pc[2]]; + pc = mem + (pc[6] << 16 | pc[7] << 8 | pc[8]); + } +} + +static void +render(SDL_Renderer *ren, SDL_Texture *tex) +{ + u_int32_t pixels[0x10000]; + u_int32_t *out; + u_int8_t *in; + + in = mem + (mem[5] << 16); + out = pixels; + for (; out < (pixels + 0x10000); *out++ = palette[*in++]) + ; + SDL_UpdateTexture(tex, 0, pixels, + 0x100 * SDL_BYTESPERPIXEL(SDL_PIXELFORMAT_BGRA32)); + SDL_RenderClear(ren); + SDL_RenderCopy(ren, tex, 0, 0); + SDL_RenderPresent(ren); +} + +int +main(int argc, char *argv[]) +{ + SDL_Window *win; + SDL_Renderer *ren; + SDL_Texture *tex; + FILE *fp; + size_t i; + int w = 256, h = 256; + u_int8_t r, g, b; + + if (argc != 2) { + fprintf(stderr, "usage: %s rom\n", argv[0]); + return EXIT_FAILURE; + } + if ((fp = fopen(argv[1], "r")) == NULL) { + fprintf(stderr, "fopen: %s\n", argv[1]); + return EXIT_FAILURE; + } + for (i = 0; (mem[i] = fgetc(fp)) != EOF && i < sizeof(mem); i++) + ; + fclose(fp); + + /* TODO: implement audio */ + win = SDL_CreateWindow("bytepusher", SDL_WINDOWPOS_UNDEFINED, + SDL_WINDOWPOS_UNDEFINED, w, h, SDL_WINDOW_SHOWN); + ren = SDL_CreateRenderer(win, -1, 0); + tex = SDL_CreateTexture(ren, SDL_PIXELFORMAT_BGRA32, + SDL_TEXTUREACCESS_STATIC, w, h); + + if (!win || !ren || !tex) { + fprintf(stderr, "SDL error: %s\n", SDL_GetError()); + return EXIT_FAILURE; + } + + for (r = 0; r < 6; r++) + for (g = 0; g < 6; g++) + for (b = 0; b < 6; b++) + palette[RGB_POS] = RGB_CALC; + + for (i = 0xd8; i < 0x100; i++) + palette[i] = 0x000000; + + for (;;) { + if (!evhandle()) + break; + cycle(); + render(ren, tex); + SDL_Delay(10); + } + + SDL_DestroyTexture(tex); + SDL_DestroyRenderer(ren); + SDL_DestroyWindow(win); + SDL_Quit(); + + return EXIT_SUCCESS; +} diff --git a/bytepusher/config.mk b/bytepusher/config.mk @@ -0,0 +1,30 @@ +# bytepusher version +VERSION = 0 + +# paths +PREFIX = /usr/local +MAN_DIR = ${PREFIX}/share/man/man1 +BIN_DIR = ${PREFIX}/bin + +# includes and libs +INCS = -Iinclude +LIBS = -Llib -lSDL2 + +# flags +CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L \ + -D_XOPEN_SOURCE=700 -DVERSION=\"${VERSION}\" +CFLAGS = -std=c99 -pedantic -Wall -Wno-deprecated-declarations -Os ${INCS} ${CPPFLAGS} +LDFLAGS = ${LIBS} + +# utils +CP = cp -f +RM = rm -f +RM_DIR = rm -rf +MV = mv +MKDIR = mkdir -p +RM_DIR = rm -rf +TAR = tar -cf +GZIP = gzip + +# compiler +CC = gcc diff --git a/bytepusher/roms/invertloopsine.BytePusher b/bytepusher/roms/invertloopsine.BytePusher Binary files differ. diff --git a/bytepusher/roms/munchingsquares.BytePusher b/bytepusher/roms/munchingsquares.BytePusher Binary files differ. diff --git a/bytepusher/roms/nyan.BytePusher b/bytepusher/roms/nyan.BytePusher Binary files differ. diff --git a/bytepusher/roms/palettetest.BytePusher b/bytepusher/roms/palettetest.BytePusher Binary files differ. diff --git a/bytepusher/roms/scrollinglogo.BytePusher b/bytepusher/roms/scrollinglogo.BytePusher Binary files differ. diff --git a/bytepusher/roms/sinescroller.BytePusher b/bytepusher/roms/sinescroller.BytePusher Binary files differ. diff --git a/fnc/Makefile b/fnc/Makefile @@ -0,0 +1,46 @@ +# See LICENSE file for copyright and license details. +# fnc - a simple finance program +.POSIX: + +PREFIX = /usr/local +MAN_DIR = ${PREFIX}/share/man/man1 +BIN_DIR = ${PREFIX}/bin + +BIN = fnc +VERSION = 0 +DIST = ${BIN}-${VERSION} +MAN1 = ${BIN}.1 + +SRC = fnc.go + +all: ${BIN} + +${BIN}: ${SRC} + go build ${SRC} + +dist: clean + mkdir -p ${DIST} + cp -fR fnc.1 fnc.go Makefile ${DIST} + tar -cf ${DIST}.tar ${DIST} + gzip ${DIST}.tar + rm -rf ${DIST} + +install: all + mkdir -p ${DESTDIR}${BIN_DIR} ${DESTDIR}${MAN_DIR} + cp -f ${BIN} ${BIN_DIR} + cp -f ${MAN1} ${DESTDIR}${MAN_DIR} + sed "s/VERSION/${VERSION}/g" < ${MAN1} > ${DESTDIR}${MAN_DIR}/${MAN1} + chmod 755 ${DESTDIR}${BIN_DIR}/${BIN} + chmod 644 ${DESTDIR}${MAN_DIR}/${MAN1} + +uninstall: + rm -f ${DESTDIR}${BIN_DIR}/${BIN} + rm -f ${DESTDIR}${MAN_DIR}/${MAN1} + +run: + ./${BIN} + +clean: + rm -f ${BIN} ${OBJ} ${DIST}.tar.gz + +.PHONY: all options clean dist install uninstall run diff --git a/fnc/fnc.1 b/fnc/fnc.1 @@ -0,0 +1,28 @@ +.Dd fnc\-VERSION +.Dt FNC 1 +.Os +.Sh NAME +.Nm fnc +.Nd a simple finance program +.Sh SYNOPSIS +.Nm +.Op Fl d Ar date +.Ar file +.Sh DESCRIPTION +.Pp +.Nm +reads a CSV file structured like this: + + Date,Item,Price + Feb2021,Foo,+1 + Mar2021,Bar,-2 + Apr2021,Baz,+3 + +The dates must also not have spaces between them +(e.g Feb 2021) in case you want to use the -d option. +.Sh OPTIONS +.Bl -tag -width -indent +.It Fl d Ar date +prints only the fields matching the specified date. +.Sh AUTHORS +.An Christos Margiolis Aq Mt christos@christosmarg.xyz diff --git a/fnc/fnc.go b/fnc/fnc.go @@ -0,0 +1,80 @@ +package main + +import ( + "encoding/csv" + "fmt" + "io" + "log" + "os" + "strconv" +) + +func usage() { + fmt.Fprintf(os.Stderr, "usage: %s [-d date] file\n", os.Args[0]); + os.Exit(1); +} + +func main() { + var path, date string; + var n, loss, gain, total float64; + var arglen int; + var dflag bool; + + arglen = len(os.Args); + if arglen - 1 == 0 { + usage(); + } + path = os.Args[arglen - 1]; + for i := 0; i < arglen; i++ { + if os.Args[i] == "-d" { + date = os.Args[i+1]; + dflag = true; + } else if os.Args[i] == "-h" { + usage(); + } + } + + f, err := os.Open(path); + if err != nil { + log.Fatal(err); + } + defer f.Close(); + + csvr := csv.NewReader(f); + if err != nil { + log.Fatal(err); + } + header, err := csvr.Read(); + if err != nil { + log.Fatal(err); + } + fmt.Println(header); + + for { + line, err := csvr.Read(); + if err != nil { + if err == io.EOF { + break; + } + log.Fatal(err); + } + if dflag && date != line[0] { + continue; + } + n, err = strconv.ParseFloat(line[2], 64); + if err != nil { + log.Fatal(err); + } + if n >= 0 { + gain += n; + } else { + loss += n; + } + total += n; + fmt.Printf("%-15s %-20s %-.2f\n", line[0], line[1], n); + } + fmt.Println(); + fmt.Printf("Loss: %.2f\n", -loss); + fmt.Printf("Gain: %.2f\n", gain); + fmt.Printf("Total: %.2f\n", total); +} diff --git a/minecurses/Makefile b/minecurses/Makefile @@ -0,0 +1,53 @@ +# minecurses - a terminal minesweeper game +.POSIX: + +include config.mk + +BIN = minecurses +DIST = ${BIN}-${VERSION} +MAN6 = ${BIN}.6 + +SRC = minecurses.c +OBJ = ${SRC:.c=.o} + +all: options ${BIN} + +options: + @echo ${BIN} build options: + @echo "CFLAGS = ${CFLAGS}" + @echo "LDFLAGS = ${LDFLAGS}" + @echo "CC = ${CC}" + +${BIN}: ${OBJ} + ${CC} ${LDFLAGS} ${OBJ} -o $@ + +.c.o: + ${CC} -c ${CFLAGS} $< + +dist: clean + ${MKDIR} ${DIST} + ${CP} -R log/ res/ config.mk defs.h LICENSE Makefile ${MAN} ${SRC} \ + README.md ${DIST} + ${TAR} ${DIST}.tar ${DIST} + ${GZIP} ${DIST}.tar + ${RM_DIR} ${DIST} + +run: + ./${BIN} + +install: all + ${MKDIR} ${DESTDIR}${BIN_DIR} ${DESTDIR}${MAN_DIR} + ${CP} ${BIN} ${BIN_DIR} + ${CP} ${MAN6} ${DESTDIR}${MAN_DIR} + sed "s/VERSION/${VERSION}/g" < ${MAN6} > ${DESTDIR}${MAN_DIR}/${MAN6} + chmod 755 ${DESTDIR}${BIN_DIR}/${BIN} + chmod 644 ${DESTDIR}${MAN_DIR}/${MAN6} + +uninstall: + ${RM} ${DESTDIR}${BIN_DIR}/${BIN} + ${RM} ${DESTDIR}${MAN_DIR}/${MAN6} + +clean: + ${RM} ${BIN} ${OBJ} ${DIST}.tar.gz + +.PHONY: all options clean dist install uninstall run diff --git a/minecurses/README.md b/minecurses/README.md @@ -0,0 +1,47 @@ +# minecurses + +A minesweeper game using `ncurses`. The game was originally made as a +university assignment of mine, but I decided to take it a bit further afterwards. + +## How to play + +The objective is to simply find and defuse all the mines, not open all the non-mine +cells, like in most minesweeper games; this make the game relatively harder. + +* Enter number of columns +* Enter number of rows +* Enter number of mines +* Move with `w`/`s`/`a`/`d` or Vim keys (`k`/`j`/`h`/`l`) +* Open cell with `[ENTER]`, or `o` +* Flag cell with `f` +* Defuse mine (only if flagged) with `g` +* You win if you defuse all the mines +* You lose in case you open a mine or you try to defuse a flagged cell not containing a mine + +Additional controls + +* `m`: Open control menu +* `r`: Restart the game +* `q`: Quit + +## Usage + +```shell +$ cd path/to/minecurses +$ make && make run +$ make clean # optional +``` +You can install `minecurses` by running `sudo make install clean`. +The binary will be installed in `/usr/local/bin`. + +## Preview + +### Start screen +![startmenu](https://user-images.githubusercontent.com/54286563/102023826-b110f780-3d96-11eb-89a3-4b0679a36a50.png) +### Gameplay +![gameplay](https://user-images.githubusercontent.com/54286563/102023832-ba9a5f80-3d96-11eb-9341-b2a07a7356de.png) + +## To Do + +* Add colors +* Fix occasional wrong mine spawning bug diff --git a/minecurses/config.mk b/minecurses/config.mk @@ -0,0 +1,30 @@ +# minecurses version +VERSION = 0 + +# paths +PREFIX = /usr/local +MAN_DIR = ${PREFIX}/share/man/man6 +BIN_DIR = ${PREFIX}/bin + +# includes and libs +INCS = -Iinclude +LIBS = -Llib -lncurses + +# flags +CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L \ + -D_XOPEN_SOURCE=700 -DVERSION=\"${VERSION}\" +CFLAGS = -std=c99 -pedantic -Wall -Os ${INCS} ${CPPFLAGS} +LDFLAGS = ${LIBS} + +# utils +CP = cp -f +RM = rm -f +RM_DIR = rm -rf +MV = mv +MKDIR = mkdir -p +RM_DIR = rm -rf +TAR = tar -cf +GZIP = gzip + +# compiler +CC = gcc diff --git a/minecurses/defs.h b/minecurses/defs.h @@ -0,0 +1,68 @@ +#ifndef DEFS_H +#define DEFS_H + +#define MOVE_UP_NORM 'k' +#define MOVE_UP_VIM 'w' +#define MOVE_DOWN_NORM 's' +#define MOVE_DOWN_VIM 'j' +#define MOVE_LEFT_NORM 'a' +#define MOVE_LEFT_VIM 'h' +#define MOVE_RIGHT_NORM 'd' +#define MOVE_RIGHT_VIM 'l' +#define MOVE_ENTER '\n' +#define MOVE_OPEN_CELL 'o' +#define MOVE_FLAG_CELL 'f' +#define MOVE_DEFUSE_CELL 'g' +#define MOVE_OPEN_MENU 'm' +#define MOVE_RESTART 'r' +#define MOVE_QUIT 'q' + +#define MINE_DEFUSED 'D' +#define CELL_FLAGGED 'F' +#define CELL_BLANK ' ' +#define CELL_MINE '*' +#define GRID_BOX "[ ]" + +#define OPT_CTRLS "m Controls" +#define OPT_QUIT "q Quit" +#define OPT_RESTART "r Restart" +#define OPT_MOVE_UP "w/k Move up" +#define OPT_MOVE_DOWN "s/j Move down" +#define OPT_MOVE_LEFT "a/h Move left" +#define OPT_MOVE_RIGHT "d/l Move right" +#define OPT_FLAG_CELL "f Flag cell" +#define OPT_DEFUSE "g Defuse (if flagged only)" +#define OPT_OPEN_CELL "[ENTER]/o Open cell" + +#define MSG_COLS "Columns (Min = %d, Max = %d): " +#define MSG_ROWS "Rows (Min = %d, Max = %d): " +#define MSG_MINES "Mines (Min = %d, Max = %d): " +#define MSG_QUIT_MENU "Press any key to quit the menu" +#define MSG_CONT "Press any key to continue" +#define MSG_CURPOS "Current position: (%d, %d) " +#define MSG_NDEFUSED "Defused mines: %d/%d" +#define MSG_WIN_1 "You defused all the mines!" +#define MSG_WIN_2 "You won :)" +#define MSG_LOSE_1 "You hit a mine! (or tried to defuse the wrong cell)" +#define MSG_LOSE_2 "Game over :(" + +#define GAME_LOST 0 +#define GAME_WON 1 + +#define YMAX(x) (getmaxy((x))) +#define XMAX(x) (getmaxx((x))) +#define YMID(x) (getmaxy((x)) >> 1) +#define XMID(x) (getmaxx((x)) >> 1) +#define SCRSPACE_X(x) ((x) * 3 + 2) +#define SCRSPACE_Y(y) ((y) + 2) +#define ARRSPACE_X(x) (((x) - 2) / 3) +#define ARRSPACE_Y(y) ((y) - 1) +#define CENTER(x, y) (((x) >> 1) - ((y) >> 1)) +#define CURS_UPDATE(m, y, x) (wmove((m)->gamewin, (y), (x))) +#define IS_MINE(m, r, c) ((m)->mineboard[(r)][(c)] == CELL_MINE) +#define IS_FLAGGED(m, r, c) ((m)->dispboard[(r)][(c)] == CELL_FLAGGED) +#define IS_BLANK(m, r, c) ((m)->dispboard[(r)][(c)] == CELL_BLANK) +#define OUT_OF_BOUNDS(m, r, c) ((r) < 0 || (r) > ((m)->rows - 1) || \ + (c) < 0 || (c) > ((m)->cols - 1)) + +#endif /* DEFS_H */ diff --git a/minecurses/minecurses.6 b/minecurses/minecurses.6 @@ -0,0 +1,39 @@ +.Dd minecurses\-VERSION +.Dt MINECURSES 6 +.Os +.Sh NAME +.Nm minecurses +.Nd a terminal minesweeper game +.Sh SYNOPSIS +.Nm +.Sh DESCRIPTION +.Nm +starts a minesweeper game using the +.Xr ncurses 3 +library to draw the TUI. +.Sh OPTIONS +The following option are used during runtime in the TUI, +not the command line. +.Bl -tag -width 8n +.It Sy q +quit game +.It Sy r +restart game +.It Sy w/k +move up on the Y axis +.It Sy s/j +move down on the Y axis +.It Sy a/h +move left on the X axis +.It Sy d/l +move right on the X axis +.It Sy f +flag cell +.It Sy g +defuse mine (if flagged only) +.It Sy ENTER/o +open cell +.Sh SEE ALSO +.Xr ncurses 3 +.Sh AUTHORS +.An Christos Margiolis Aq Mt christos@christosmarg.xyz diff --git a/minecurses/minecurses.c b/minecurses/minecurses.c @@ -0,0 +1,372 @@ +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include <ncurses.h> + +#include "defs.h" + +struct minecurses { + WINDOW *gamewin; + char **dispboard; + char **mineboard; + int rows; + int cols; + int nmines; + int ndefused; + int move; + int x; + int y; + int gameover; +}; + +static void gamereset(struct minecurses *); +static void gamerestart(struct minecurses *); +static void gamestart(struct minecurses *); +static int valset(int, const char *, int, int); +static int adjcount(const struct minecurses *, int, int); +static void boardsdealloc(struct minecurses *); +static void cellreveal(const struct minecurses *); +static void boardprint(const struct minecurses *); +static WINDOW *gamewininit(int, int); +static void menuopts(void); +static void endscreen(struct minecurses *, int); +static void *emalloc(size_t); + +static void +gamereset(struct minecurses *m) +{ + size_t i, j, r, c; + + echo(); + m->cols = valset(4, MSG_COLS, 5, ARRSPACE_X(XMAX(stdscr)) - 2); + m->rows = valset(3, MSG_ROWS, 5, ARRSPACE_Y(YMAX(stdscr)) - 3); + m->nmines = valset(2, MSG_MINES, 1, m->rows * m->cols - 15); + m->x = m->y = 0; + m->ndefused = 0; + m->gameover = 0; + noecho(); + + menuopts(); + if (m->gamewin == NULL) + m->gamewin = gamewininit(m->rows, m->cols); + + /* allocate memory for the boards */ + m->dispboard = emalloc(m->rows * sizeof(char *)); + m->mineboard = emalloc(m->rows * sizeof(char *)); + for (i = 0; i < m->rows; i++) { + m->dispboard[i] = emalloc(m->cols); + m->mineboard[i] = emalloc(m->cols); + } + + /* place mines */ + srand(time(NULL)); + for (i = 0; i < m->nmines; i++) { + r = rand() % m->rows; + c = rand() % m->cols; + m->mineboard[r][c] = CELL_MINE; + } + + /* TODO: do it in one loop */ + /* add numbers */ + for (i = 0; i < m->rows; i++) { + for (j = 0; j < m->cols; j++) { + if (!IS_MINE(m, i, j)) + m->mineboard[i][j] = adjcount(m, i, j) + '0'; + /* in the meantime, initialize dispboard */ + m->dispboard[i][j] = CELL_BLANK; + } + } + + /* fill spaces */ + for (i = 0; i < m->rows; i++) + for (j = 0; j < m->cols; j++) + if (!IS_MINE(m, i, j) && m->mineboard[i][j] == '0') + m->mineboard[i][j] = '-'; +} + +static void +gamerestart(struct minecurses *m) +{ + boardsdealloc(m); + gamereset(m); +} + +#define bx m->x +#define by m->y + +static void +gamestart(struct minecurses *m) +{ + static int y = 1, x = 2; + + for (;;) { + erase(); + // is this necessary? + delwin(m->gamewin); + m->gamewin = gamewininit(m->rows, m->cols); + refresh(); + boardprint(m); + + CURS_UPDATE(m, y, x); + bx = ARRSPACE_X(x); + by = ARRSPACE_Y(y); + + /* session info */ + mvprintw(0, 0, MSG_CURPOS, bx, by); + mvprintw(0, XMID(stdscr) - ((strlen(MSG_NDEFUSED) - 2) >> 1), + MSG_NDEFUSED, m->ndefused, m->nmines); + mvprintw(0, XMAX(stdscr) - strlen(OPT_CTRLS), OPT_CTRLS); + + refresh(); + + /* handle moves */ + switch (m->move = wgetch(m->gamewin)) { + case MOVE_UP_NORM: /* FALLTHROUGH */ + case MOVE_UP_VIM: + if (--y < 1) + y = 1; + break; + case MOVE_DOWN_NORM: /* FALLTHROUGH */ + case MOVE_DOWN_VIM: + if (++y > XMAX(m->gamewin) - 2) + y = YMAX(m->gamewin) - 2; + break; + case MOVE_LEFT_NORM: /* FALLTHROUGH */ + case MOVE_LEFT_VIM: + x -= 3; + if (x < 2) + x = 2; + break; + case MOVE_RIGHT_NORM: /* FALLTHROUGH */ + case MOVE_RIGHT_VIM: + x += 3; + if (x > XMAX(m->gamewin) - 3) + x = XMAX(m->gamewin) - 3; + break; + case MOVE_ENTER: /* FALLTHROUGH */ + case MOVE_OPEN_CELL: + m->dispboard[by][bx] = m->mineboard[by][bx]; + m->gameover = IS_MINE(m, by, bx); + cellreveal(m); + break; + case MOVE_FLAG_CELL: + if (IS_FLAGGED(m, by, bx)) + m->dispboard[by][bx] = CELL_BLANK; + else if (!IS_FLAGGED(m, by, bx) && !IS_BLANK(m, by, bx)) + break; + else + m->dispboard[by][bx] = CELL_FLAGGED; + cellreveal(m); + break; + case MOVE_DEFUSE_CELL: + if (IS_FLAGGED(m, by, bx) && IS_MINE(m, by, bx)) { + m->ndefused++; + m->dispboard[by][bx] = MINE_DEFUSED; + m->mineboard[by][bx] = MINE_DEFUSED; + cellreveal(m); + } else if (IS_FLAGGED(m, by, bx) && !IS_MINE(m, by, bx)) + m->gameover = 1; + break; + case MOVE_OPEN_MENU: + menuopts(); + box(m->gamewin, 0, 0); + boardprint(m); + break; + case MOVE_RESTART: + gamerestart(m); + break; + } + + if (OUT_OF_BOUNDS(m, by, bx) + || m->ndefused > m->nmines + || m->gameover + || m->move == MOVE_QUIT) + break; + } + + if (m->gameover) + endscreen(m, GAME_LOST); + else if (m->ndefused == m->nmines) + endscreen(m, GAME_WON); +} + +#undef bx +#undef by + +static int +valset(int offy, const char *msg, int min, int max) +{ + int val; + + do { + mvprintw(YMAX(stdscr)-offy, 1, msg, min, max); + scanw("%d", &val); + } while (val < min || val > max); + return val; +} + +static int +adjcount(const struct minecurses *m, int r, int c) +{ + int n = 0; + + if (!OUT_OF_BOUNDS(m, r, c-1) && IS_MINE(m, r, c-1)) n++; // north + if (!OUT_OF_BOUNDS(m, r, c+1) && IS_MINE(m, r, c+1)) n++; // south + if (!OUT_OF_BOUNDS(m, r+1, c) && IS_MINE(m, r+1, c)) n++; // east + if (!OUT_OF_BOUNDS(m, r-1, c) && IS_MINE(m, r-1, c)) n++; // west + if (!OUT_OF_BOUNDS(m, r+1, c-1) && IS_MINE(m, r+1, c-1)) n++; // north-east + if (!OUT_OF_BOUNDS(m, r-1, c-1) && IS_MINE(m, r-1, c-1)) n++; // north-west + if (!OUT_OF_BOUNDS(m, r+1, c+1) && IS_MINE(m, r+1, c+1)) n++; // south-east + if (!OUT_OF_BOUNDS(m, r-1, c+1) && IS_MINE(m, r-1, c+1)) n++; // south-west + + return n; +} + +static void +boardsdealloc(struct minecurses *m) +{ + size_t i = 0; + + if (!m->dispboard && !m->mineboard) { + for (; i < m->rows; i++) { + free(m->dispboard[i]); + free(m->mineboard[i]); + } + free(m->dispboard); + free(m->mineboard); + } +} + +static void +cellreveal(const struct minecurses *m) +{ + int y = m->y + 1; + int x = SCRSPACE_X(m->x); + + mvwaddch(m->gamewin, y, x, m->dispboard[m->y][m->x]); +} + +static void +boardprint(const struct minecurses *m) +{ + size_t i, j, x, y; + + wattroff(m->gamewin, A_BOLD); + for (i = 1; i <= m->rows; i++) { + wmove(m->gamewin, i, 1); + for (j = 0; j < m->cols; j++) + wprintw(m->gamewin, GRID_BOX); + } + + wattron(m->gamewin, A_BOLD); + for (i = 0, y = 1; i < m->rows; i++, y++) + for (j = 0, x = 2; j < m->cols; j++, x += 3) + mvwaddch(m->gamewin, y, x, m->dispboard[i][j]); +} + +static WINDOW * +gamewininit(int rows, int cols) +{ + WINDOW *gw; + int wr, wc, wy, wx; + + wr = SCRSPACE_Y(rows); + wc = SCRSPACE_X(cols); + wy = CENTER(YMAX(stdscr), wr); + wx = CENTER(XMAX(stdscr), wc); + gw = newwin(wr, wc, wy, wx); + wattron(gw, A_BOLD); + box(gw, 0, 0); + wattroff(gw, A_BOLD); + + return gw; +} + +static void +menuopts(void) +{ + WINDOW *opts; + int w, h, wy, wx; + + w = 36; + h = 13; + wy = CENTER(YMAX(stdscr), h); + wx = CENTER(XMAX(stdscr), w); + opts = newwin(h, w, wy, wx); + box(opts, 0, 0); + + /* fill menu */ + mvwprintw(opts, 1, 1, OPT_QUIT); + mvwprintw(opts, 2, 1, OPT_RESTART); + mvwprintw(opts, 3, 1, OPT_MOVE_UP); + mvwprintw(opts, 4, 1, OPT_MOVE_DOWN); + mvwprintw(opts, 5, 1, OPT_MOVE_LEFT); + mvwprintw(opts, 6, 1, OPT_MOVE_RIGHT); + mvwprintw(opts, 7, 1, OPT_FLAG_CELL); + mvwprintw(opts, 8, 1, OPT_DEFUSE); + mvwprintw(opts, 9, 1, OPT_OPEN_CELL); + mvwprintw(opts, 11, 1, MSG_QUIT_MENU); + + wgetch(opts); + delwin(opts); +} + +static void +endscreen(struct minecurses *m, int state) +{ + curs_set(0); + wclear(m->gamewin); + wrefresh(m->gamewin); + attron(A_BOLD); + switch (state) { + case GAME_WON: + mvprintw(YMID(stdscr)-2, XMID(stdscr)-11, MSG_WIN_1); + mvprintw(YMID(stdscr)-1, XMID(stdscr)-3, MSG_WIN_2); + break; + case GAME_LOST: + mvprintw(YMID(stdscr)-2, XMID(stdscr)-24, MSG_LOSE_1); + mvprintw(YMID(stdscr)-1, XMID(stdscr)-4, MSG_LOSE_2); + // TODO: print mine board + break; + } + mvprintw(YMID(stdscr), XMID(stdscr)-11, MSG_CONT); + refresh(); + attroff(A_BOLD); + getchar(); + // TODO: restart option +} + +static void * +emalloc(size_t nb) +{ + void *p; + + if ((p = malloc(nb)) == NULL) { + fputs("malloc", stderr); + exit(EXIT_FAILURE); + } + return p; +} + +int +main(int argc, char *argv[]) +{ + struct minecurses m; + + if (!initscr()) { + fputs("initscr", stderr); + return 1; + } + noecho(); + cbreak(); + + gamereset(&m); + gamestart(&m); + + boardsdealloc(&m); + delwin(m.gamewin); + endwin(); + + return EXIT_SUCCESS; +} diff --git a/morse/dash.wav b/morse/dash.wav Binary files differ. diff --git a/morse/dot.wav b/morse/dot.wav Binary files differ. diff --git a/morse/morse.cpp b/morse/morse.cpp @@ -0,0 +1,96 @@ +#include <iostream> +#include <map> +#include <string> +#include <SDL2/SDL.h> +#include <SDL2/SDL_mixer.h> + +static void +play(Mix_Chunk *sound) +{ + Mix_PlayChannel(-1, sound, 0); + while (Mix_Playing(-1) != 0) + SDL_Delay(200); +} + +int +main(int argc, char *argv[]) +{ + Mix_Chunk *dot = nullptr; + Mix_Chunk *dash = nullptr; + std::string in, out; + std::map<char, std::string>::const_iterator it; + std::map<char, std::string> morsetable = { + {'a', ".-" }, {'A', ".-" }, + {'b', "-..." }, {'B', "-..." }, + {'c', "-.-." }, {'C', "-.-." }, + {'d', "-.." }, {'D', "-.." }, + {'e', "." }, {'E', "." }, + {'f', "..-." }, {'F', "..-." }, + {'g', "--." }, {'G', "--." }, + {'h', "...." }, {'H', "...." }, + {'i', ".." }, {'I', ".." }, + {'j', ".---" }, {'J', ".---" }, + {'k', "-.-" }, {'K', "-.-" }, + {'l', ".-.." }, {'L', ".-.." }, + {'m', "--" }, {'M', "--" }, + {'n', "-." }, {'N', "-." }, + {'o', "---" }, {'O', "---" }, + {'p', ".--." }, {'P', ".--." }, + {'q', "--.-" }, {'Q', "--.-" }, + {'r', ".-." }, {'R', ".-." }, + {'s', "..." }, {'S', "..." }, + {'t', "-" }, {'T', "-" }, + {'u', "..-" }, {'U', "..-" }, + {'v', "...-" }, {'V', "...-" }, + {'w', ".--" }, {'W', ".--" }, + {'x', "-..-" }, {'X', "-..-" }, + {'y', "-.--" }, {'Y', "-.--" }, + {'z', "--.." }, {'Z', "--.." }, + {'&', ".-..." }, {'\'', ".----."}, + {'@', ".--.-." }, {':', "---..." }, + {'(', "-.--." }, {')', "-.--.-" }, + {',', "--..--" }, {'=', "-...-" }, + {'!', "-.-.--" }, {'.', ".-.-.-" }, + {'-', "-....-" }, {'+', ".-.-." }, + {'\"', ".-..-."}, {'\?', "..--.."}, + {'/', "-..-." }, {' ', " / " } + }; + + if (SDL_Init(SDL_INIT_AUDIO) == -1) + return -1; + Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 1, 4096); + dot = Mix_LoadWAV("dot.wav"); + dash = Mix_LoadWAV("dash.wav"); + + std::cout << "Press CTRL+C to exit" << std::endl; + for (;;) { + std::cout << "> "; + std::getline(std::cin, in); + for (const char& c : in) { + it = morsetable.find(c); + if (morsetable.find(c) != morsetable.end()) + out += it->second; + else + std::cerr << "Character '" << c << + "' not found." << std::endl; + out += " "; + } + if (!out.empty()) { + std::cout << out << std::endl; + for (const char& c : out) { + if (c == '.') + play(dot); + else if (c == '-') + play(dash); + } + out.clear(); + } + } + + Mix_FreeChunk(dot); + Mix_FreeChunk(dash); + Mix_CloseAudio(); + SDL_Quit(); + + return 0; +} diff --git a/other/bounce.c b/other/bounce.c @@ -0,0 +1,55 @@ +#include <ncurses.h> +#include <stdio.h> +#include <unistd.h> + +struct ball { + int x; + int y; + int vx; + int vy; + int xmax; + int ymax; +}; + +static void +init_curses(void) +{ + initscr(); + cbreak(); + noecho(); + curs_set(0); +} + +static void +collision(struct ball *b) +{ + if (b->y < 2 || b->y > b->ymax-1) + b->vy *= -1.0f; + if (b->x < 1 || b->x > b->xmax-1) + b->vx *= -1.0f; + b->y += b->vy; + b->x += b->vx; +} + +int +main(int argc, char *argv[]) +{ + struct ball b = {1, 2, 1, 1, 0, 0}; + + init_curses(); + getmaxyx(stdscr, b.ymax, b.xmax); + + for (;;) + { + erase(); + collision(&b); + mvaddch(b.y, b.x, 'O'); + mvprintw(0, 0, "(x, y) = (%d, %d)", b.x, b.y); + mvhline(1, 0, ACS_HLINE, b.xmax); + refresh(); + usleep(15000); + } + endwin(); + + return 0; +} diff --git a/other/mandelbrot.c b/other/mandelbrot.c @@ -0,0 +1,59 @@ +#include <math.h> +#include <stdio.h> +#include <stdlib.h> + +#define IMGW 1920 +#define IMGH 1080 +#define MAXN 1024 +#define MINR (-1.5) +#define MAXR 0.7 +#define MINI (-1.0) +#define MAXI 1.0 + +#define TOREAL(x, imgw, minr, maxr) (x * ((maxr - minr) / imgw) + minr) +#define TOIMGN(y, imgh, mini, maxi) (y * ((maxi - mini) / imgh) + mini) + +static int +fmandelbrot(double cr, double ci) +{ + int i = 0; + double zr = 0.0, zi = 0.0; + double tmp; + + for ( ; i < MAXN && (zr * zr + zi * zi) < 4.0; i++) { + tmp = zr * zr - zi * zi + cr; + zi = 2.0 * zr * zi + ci; + zr = tmp; + } + return i; +} + +int +main(int argc, char *argv[]) +{ + FILE *fp; + int x, y, n, r, g, b; + double cr, ci; + + if ((fp = fopen("mandelbrot_output.ppm", "w")) == NULL) { + fprintf(stderr, "Cannot open output file. Exiting..."); + return EXIT_FAILURE; + } + fprintf(fp, "P3\n%d %d\n256\n", IMGW, IMGH); + + for (y = 0; y < IMGH; y++) { + for (x = 0; x < IMGW; x++) { + cr = TOREAL(x, IMGW, MINR, MAXR); + ci = TOIMGN(y, IMGH, MINI, MAXI); + n = fmandelbrot(cr, ci); + r = (n % 256); + g = ((int)(n * sinf(M_PI)) % 256); + b = ((n * 3) % 256); + fprintf(fp, "%d %d %d ", r, g, b); + } + fprintf(fp, "\n"); + } + fclose(fp); + + return 0; +} diff --git a/other/nnc.cpp b/other/nnc.cpp @@ -0,0 +1,167 @@ +#include <algorithm> +#include <cmath> +#include <cstdlib> +#include <ctime> +#include <vector> +#include <ncurses.h> + +static constexpr int ymax() +{ + return getmaxy(stdscr); +} + +static constexpr int xmax() +{ + return getmaxx(stdscr); +} + +struct Color { + int x, y; + int color; + + Color(int x, int y, int color) + :x(x), y(y), color(color) {} + + constexpr int dist(const Color& c) + { + int dx = this->x - c.x; + int dy = this->y - c.y; + + return std::sqrt(dx * dx + dy * dy); + } +}; + +struct Blue: public Color { + Blue(int x, int y, int color) + :Color(x, y, color) {} +}; + +struct Green: public Color { + Green(int x, int y, int color) + :Color(x, y, color) {} +}; + +struct White: public Color { + White(int x, int y, int color) + :Color(x, y, color) {} +}; + +static void +init_curses() +{ + initscr(); + cbreak(); + noecho(); + curs_set(0); + start_color(); + init_pair(1, COLOR_BLUE, COLOR_BLUE); + init_pair(2, COLOR_GREEN, COLOR_GREEN); + init_pair(3, COLOR_WHITE, COLOR_WHITE); +} + +static void +makepts(std::vector<Color *>& points) +{ + int x, y; + + for (std::size_t i = 0; i < 5; i++) { + x = std::rand() % (xmax() - 1); + y = std::rand() % (ymax() - 1); + points.push_back(new Blue(x, y, 1)); + } + for (std::size_t i = 0; i < 5; i++) { + x = std::rand() % (xmax() - 1); + y = std::rand() % (ymax() - 1); + points.push_back(new Green(x, y, 2)); + } +} + +static void +makewts(std::vector<White *>& whites) +{ + int x, y; + + for (std::size_t i = 0; i < 5; i++) { + x = std::rand() % (xmax() - 1); + y = std::rand() % (ymax() - 1); + whites.push_back(new White(x, y, 3)); + } +} + +template<typename T> static void +print(const std::vector<T *>& vec) +{ + for (auto& v : vec) { + attron(COLOR_PAIR(v->color)); + mvaddch(v->y, v->x, ACS_CKBOARD); + attroff(COLOR_PAIR(v->color)); + } +} + +static std::vector<int> +calc_dists(const std::vector<Color *>& points, const White& w) +{ + std::vector<int> dists; + + for (auto& point : points) + dists.push_back(point->dist(w)); + return dists; +} + +static void +find_nn(const std::vector<Color *>& points, std::vector<White *>& whites) +{ + std::vector<int> dists; + int mindist; + + for (const auto& point : points) { + for (auto&& white : whites) { + dists = calc_dists(points, *white); + mindist = *std::min_element(dists.begin(), dists.end()); + if (point->dist(*white) == mindist) + white->color = point->color; + } + } +} + +template<typename T> static void +dealloc(std::vector<T *>& vec) +{ + for (auto&& v : vec) + if (v != nullptr) + delete v; + if (!vec.empty()) + vec.clear(); +} + +int +main(int argc, char **argv) +{ + init_curses(); + std::srand(std::time(nullptr)); + + std::vector<Color *> points; + std::vector<White *> whites; + makepts(points); + makewts(whites); + + erase(); + print<Color>(points); + print<White>(whites); + refresh(); + getch(); + + find_nn(points, whites); + + erase(); + print<Color>(points); + print<White>(whites); + refresh(); + getch(); + + endwin(); + dealloc<Color>(points); + dealloc<White>(whites); + + return 0; +} diff --git a/other/snake.cpp b/other/snake.cpp @@ -0,0 +1,184 @@ +#include <chrono> +#include <cstdlib> +#include <ctime> +#include <list> +#include <thread> + +#include <ncurses.h> + +#define XMAX (getmaxx(stdscr)) +#define YMAX (getmaxy(stdscr)) + +struct Snake { + struct Seg { + int x; + int y; + }; + std::list<Seg> body; + int x; + int y; + int score; + bool dead; + + Snake(); + void update(int key); + void grow(); + void draw(); + bool collided(); +}; + +struct Food { + int x; + int y; + + Food(); + void spawn(); + void draw(); +}; + +Snake::Snake() +{ + y = YMAX >> 1; + x = XMAX >> 1; + body = {{x, y}, {x + 1, y + 1}}; + score = 1; + dead = false; +} + +void +Snake::update(int key) +{ + switch (key) { + case KEY_UP: + y--; + body.push_front({body.front().x, body.front().y - 1}); + break; + case KEY_DOWN: + y++; + body.push_front({body.front().x, body.front().y + 1}); + break; + case KEY_LEFT: + x--; + body.push_front({body.front().x - 1, body.front().y}); + break; + case KEY_RIGHT: + x++; + body.push_front({body.front().x + 1, body.front().y}); + break; + } + body.pop_back(); +} + +void +Snake::grow() +{ + for (int i = 0; i < 3; i++) + body.push_back({body.back().x, body.back().y}); +} + +void +Snake::draw() +{ + for (const auto& b : body) + mvaddch(b.y, b.x, ACS_CKBOARD); +} + +bool +Snake::collided() +{ + dead = y < 2 || y > YMAX - 1 || x < 1 || x > XMAX - 1; + for (std::list<Seg>::iterator i = body.begin(); i != body.end(); i++) + if (i != body.begin() + && i->x == body.front().x + && i->y == body.front().y) + dead = true; + return dead; +} + +Food::Food() +{ + x = std::rand() % XMAX - 1; + y = std::rand() % (YMAX - 2) + 2; +} + +void +Food::spawn() +{ + x = std::rand() % XMAX - 1; + y = std::rand() % (YMAX - 2) + 2; +} + +void +Food::draw() +{ + mvaddch(y, x, 'O'); +} + +static void +initcurses() +{ + initscr(); + cbreak(); + noecho(); + curs_set(0); + keypad(stdscr, true); + nodelay(stdscr, true); +} + +static bool +kbhit() +{ + int c; + + if ((c = getch()) != ERR) { + ungetch(c); + return true; + } + return false; +} + +int +main(int argc, char *argv[]) +{ + initcurses(); + std::srand(std::time(nullptr)); + + Snake snake; + Food food; + int key, nextkey; + + key = KEY_RIGHT; + + for (;;) { + erase(); + if (kbhit()) { + if ((nextkey = getch()) != key) + key = nextkey; + else + continue; + } + + snake.update(key); + if (snake.collided() || key == 'q') + break; + + if (snake.body.front().y == food.y + && snake.body.front().x == food.x) { + food.spawn(); + snake.grow(); + snake.score++; + } + + food.draw(); + snake.draw(); + + mvprintw(0, 0, "Score: %d", snake.score); + mvhline(1, 0, ACS_HLINE, XMAX); + refresh(); + std::this_thread::sleep_for(std::chrono::milliseconds(60)); + } + + endwin(); + + return 0; +} diff --git a/shitcoin/Makefile b/shitcoin/Makefile @@ -0,0 +1,52 @@ +# shitcoin - a cryptocurrency made as an experiment +.POSIX: + +include config.mk + +BIN = shitcoin +DIST = ${BIN}-${VERSION} +MAN1 = ${BIN}.1 + +SRC = shitcoin.c +OBJ = ${SRC:.c=.o} + +all: options ${BIN} + +options: + @echo ${BIN} build options: + @echo "CFLAGS = ${CFLAGS}" + @echo "LDFLAGS = ${LDFLAGS}" + @echo "CC = ${CC}" + +${BIN}: ${OBJ} + ${CC} ${LDFLAGS} ${OBJ} -o $@ + +.c.o: + ${CC} -c ${CFLAGS} $< + +dist: clean + ${MKDIR} ${DIST} + ${CP} -R config.mk shitcoin.c Makefile LICENSE README ${DIST} + ${TAR} ${DIST}.tar ${DIST} + ${GZIP} ${DIST}.tar + ${RM_DIR} ${DIST} + +run: + ./${BIN} + +install: all + ${MKDIR} ${DESTDIR}${BIN_DIR} ${DESTDIR}${MAN_DIR} + ${CP} ${BIN} ${BIN_DIR} + ${CP} ${MAN1} ${DESTDIR}${MAN_DIR} + sed "s/VERSION/${VERSION}/g" < ${MAN1} > ${DESTDIR}${MAN_DIR}/${MAN1} + chmod 755 ${DESTDIR}${BIN_DIR}/${BIN} + chmod 644 ${DESTDIR}${MAN_DIR}/${MAN1} + +uninstall: + ${RM} ${DESTDIR}${BIN_DIR}/${BIN} + ${RM} ${DESTDIR}${MAN_DIR}/${MAN1} + +clean: + ${RM} ${BIN} ${OBJ} ${DIST}.tar.gz + +.PHONY: all options clean dist install uninstall run diff --git a/shitcoin/README b/shitcoin/README @@ -0,0 +1,18 @@ +shitcoin - a useless cryptocurrency +==================================== +don't use it, it's just for fun + +Installation +------------- +Edit config.mk first + + $ make + # make install clean + +shitcoin will be installed in /usr/local/bin by default. + +To-Do +----- +- sign transactions +- generate key pairs +- implement simple wallet diff --git a/shitcoin/config.mk b/shitcoin/config.mk @@ -0,0 +1,30 @@ +# shitcoin version +VERSION = 0 + +# paths +PREFIX = /usr/local +MAN_DIR = ${PREFIX}/share/man/man1 +BIN_DIR = ${PREFIX}/bin + +# includes and libs +INCS = -Iinclude +LIBS = -Llib -lmd + +# flags +CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L \ + -D_XOPEN_SOURCE=700 -DVERSION=\"${VERSION}\" +CFLAGS = -std=c99 -pedantic -Wall -Os ${INCS} ${CPPFLAGS} +LDFLAGS = ${LIBS} + +# utils +CP = cp -f +RM = rm -f +RM_DIR = rm -rf +MV = mv +MKDIR = mkdir -p +RM_DIR = rm -rf +TAR = tar -cf +GZIP = gzip + +# compiler +CC = cc diff --git a/shitcoin/shitcoin.c b/shitcoin/shitcoin.c @@ -0,0 +1,276 @@ +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include <sha256.h> + +#define HASH_LEN 64 +#define PENDING_MAX 128 + +struct data { + char *saddr; + char *raddr; + long amount; +}; + +struct block { + struct data *data; + char hash[HASH_LEN + 1]; + char prevhash[HASH_LEN + 1]; + char tstmp[20]; + int nonce; +}; + +struct blockchain { + struct block **blocks; + struct block *pending[PENDING_MAX]; + size_t nblocks; + size_t npending; + int difficulty; + int reward; +}; + +static void transaction(const char *, const char *, long); +static struct block *newblock(const char *, const char *, long, const char *); +static char *calchash(struct block *); +static void initchain(void); +static void minepending(const char *); +static void mineblock(struct block *); +static int validchain(void); +static struct block *lastblock(void); +static long balance(const char *); +static void printchain(void); +static void cleanchain(void); +static void *emalloc(size_t); +static void die(const char *, ...); + +static struct blockchain *chain; + +static void +transaction(const char *from, const char *to, long amount) +{ + if (chain->npending < PENDING_MAX) + chain->pending[chain->npending++] = + newblock(from, to, amount, NULL); + else + fprintf(stderr, "transaction array is full\n"); +} + +static struct block * +newblock(const char *saddr, const char *raddr, long amount, const char *prevhash) +{ + struct block *b; + struct tm *tm; + time_t rtime; + + b = emalloc(sizeof(struct block)); + b->data = emalloc(sizeof(struct data)); + b->data->saddr = strdup(saddr); + b->data->raddr = strdup(raddr); + b->data->amount = amount; + time(&rtime); + tm = localtime(&rtime); + strftime(b->tstmp, sizeof(b->tstmp), "%F %T", tm); + strcpy(b->prevhash, prevhash == NULL ? "" : prevhash); + strcpy(b->hash, calchash(b)); + b->nonce = 0; + + return b; +} + +static char * +calchash(struct block *b) +{ + SHA256_CTX sha256; + unsigned char hash[SHA256_DIGEST_LENGTH]; + char buf[HASH_LEN + 19 + strlen(b->data->saddr) + strlen(b->data->raddr) + 10 + 10 + 1]; + char *res; + int i = 0; + + res = emalloc(HASH_LEN + 1); + sprintf(buf, "%s%s%s%s%ld%d", + b->prevhash, b->tstmp, + b->data->saddr, b->data->raddr, b->data->amount, b->nonce); + + SHA256_Init(&sha256); + SHA256_Update(&sha256, buf, strlen(buf)); + SHA256_Final(hash, &sha256); + for (; i < SHA256_DIGEST_LENGTH; i++) + sprintf(&res[i << 1], "%02x", hash[i]); + res[HASH_LEN] = '\0'; + + return res; +} + +static void +initchain(void) +{ + chain = emalloc(sizeof(struct blockchain)); + chain->blocks = emalloc(sizeof(struct block *)); + memset(chain->pending, 0, sizeof(chain->pending)); + chain->nblocks = 1; + chain->npending = 0; + chain->difficulty = 4; + chain->reward = 100; + chain->blocks[0] = newblock("Genesis", "Genesis", 0, "0"); +} + +static void +minepending(const char *rewaddr) +{ + struct block *b, *last; + int i = 0; + + if (chain->npending < 1) + return; + + if ((chain->blocks = realloc(chain->blocks, + sizeof(struct block *) * (chain->nblocks + chain->npending + 1))) == NULL) + die("realloc:"); + + for (; i < chain->npending; i++) { + b = chain->pending[i]; + last = lastblock(); + if (!strcmp(b->prevhash, "")) + strcpy(b->prevhash, last->hash); + mineblock(b); + chain->blocks[chain->nblocks++] = b; + } + chain->npending = 0; + memset(chain->pending, 0, sizeof(chain->pending)); + transaction("Mining Award", rewaddr, chain->reward); +} + +static void +mineblock(struct block *b) +{ + int d = chain->difficulty, i = 0; + char z[d]; + + for (; i < d; i++) + z[i] = '0'; + while (strncmp(b->hash, z, d)) { + b->nonce++; + strcpy(b->hash, calchash(b)); + } + printf("struct block mined: %s\n", b->hash); +} +static struct block * +lastblock(void) +{ + return chain->blocks[chain->nblocks - 1]; +} + +static int +validchain(void) +{ + int i = 0; + + for (; i < chain->nblocks; i++) { + if (i != 0 && strcmp(chain->blocks[i]->prevhash, + chain->blocks[i-1]->hash)) + return 0; + if (i != 0 && strcmp(chain->blocks[i]->hash, + calchash(chain->blocks[i]))) + return 0; + } + + return 1; +} + +static long +balance(const char *addr) +{ + long bal = 0; + int i; + + for (i = 0; i < chain->nblocks; i++) { + if (!strcmp(chain->blocks[i]->data->saddr, addr)) + bal -= chain->blocks[i]->data->amount; + if (!strcmp(chain->blocks[i]->data->raddr, addr)) + bal += chain->blocks[i]->data->amount; + } + + return bal; +} + +static void +printchain(void) +{ + int i = 0; + + for (; i < chain->nblocks; i++) { + printf("HASH: %s\n", chain->blocks[i]->hash); + printf("PREVHASH: %s\n", chain->blocks[i]->prevhash); + printf("TIMESTAMP: %s\n", chain->blocks[i]->tstmp); + printf("DATA:\n"); + printf(" FROM: %s\n", chain->blocks[i]->data->saddr); + printf(" TO: %s\n", chain->blocks[i]->data->raddr); + printf(" AMOUNT: %ld\n", chain->blocks[i]->data->amount); + printf("\n"); + } +} + +static void +cleanchain(void) +{ + int i = 0; + + for (; i < chain->nblocks; i++) { + free(chain->blocks[i]->data->saddr); + free(chain->blocks[i]->data->raddr); + free(chain->blocks[i]->data); + free(chain->blocks[i]); + } + free(chain->blocks); + free(chain); +} + +static void * +emalloc(size_t nb) +{ + void *p; + + if ((p = malloc(nb)) == NULL) + die("malloc:"); + + return p; +} + +static void +die(const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); + + if (fmt[0] && fmt[strlen(fmt)-1] == ':') { + fputc(' ', stderr); + perror(NULL); + } else + fputc('\n', stderr); + + exit(EXIT_FAILURE); +} + +int +main(int argc, char *argv[]) +{ + initchain(); + + transaction("Christos", "Lol", 1000); + transaction("N", "Lol", 1000); + minepending("miner"); + + printchain(); + printf("Valid chain: %s\n", validchain() ? "Yes" : "No"); + printf("Lol's balance: %ld\n", balance("Lol")); + + cleanchain(); + + return 0; +}