├── .gitignore ├── README.md ├── arduino ├── README.md └── botnet-fishbowl.ino ├── golang ├── README.md ├── botnet-fishbowl.go ├── go.mod └── go.sum └── micropython ├── README.md └── botnet-fishbowl.mpy /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | botnet-fishbowl.exe~ 3 | botnet-fishbowl.exe 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # botnet-fishbowl 2 | Use random bots scanning the internet to seed a Conways Game of Life running on a small LCD on my desk 3 | 4 | Conways Game of Life tends to reach a state where it becomes stable, but it certainly really fun to look at. The general gist of this project is very simple: Use bots scanning the internet to re-seed the game state. 5 | 6 | The code is basically as follows regardless of platform: 7 | * Bind to TCP port 6666 8 | * Initialize GOL with random seed 9 | * LOOP 10 | * * IF: we have new data on port 6666, re-seed gamestate 11 | * * ELSE: Animate and process the next step of GOL 12 | 13 | Included in this repo is: 14 | * A golang version which can be compiled for any computer/rasp pi. (.go) 15 | * A arduino version intended for an ESP32 M5STACK (.ino) 16 | * A micropython version intended for and ESP32 M5STACK (.mpy) which still needs the networking figured out. 17 | 18 | Basic compilation instructions are included in subfolders. 19 | 20 | --- 21 | 22 | "Cool, it binds to port 6666. How do I get actual bots to send traffic?" 23 | * Port forwarding and Tunneling. 24 | 25 | Spin up a small linux VM with a public IP on a cloud provider (which bots will inevitably scan) 26 | 27 | I'm a big fan of autossh (https://linux.die.net/man/1/autossh) which can be used as follows to forwawrd traffic for port 6666 on the cloud VM to port 6666 on you local machine through an SSH reverse tunnel. 28 | 29 | ``` 30 | /usr/bin/autossh -M 0 -N -o "ServerAliveInterval 15" -o "ServerAliveCountMax 3" -o "ConnectTimeout 10" -o "ExitOnForwardFailure yes" -i /home/user/.ssh/private_rsa -p 22 users@ -R 6666:localhost:6666 31 | ``` 32 | 33 | "But bots don't typically scan port 6666!" 34 | 35 | Some do, but you likely want to pick up traffic from commonly scanned ports like 21 (FTP), 139 (SMB), 3389 (RDP) etc... 36 | 37 | Use socat (https://linux.die.net/man/1/socat) 38 | 39 | ``` 40 | socat TCP-LISTEN:3389,fork TCP:localhost:6666 41 | ``` 42 | 43 | Traffic will come in on port 3389 of the cloud VM and be redirected to localhost port 6666 on the cloud VM. If your SSH reverse tunnel listed above is listening on port 6666, it will be routed over the tunnel, into your home network, and effect the game state of the LCD on your desk. 44 | 45 | 46 | Between these two tools, you can connect pretty much anything. -------------------------------------------------------------------------------- /arduino/README.md: -------------------------------------------------------------------------------- 1 | Written for an ESP32 M5Stack Core. 2 | 3 | Follow initial setup here: https://docs.m5stack.com/#/en/quick_start/m5core/m5stack_core_get_started_Arduino_Windows 4 | 5 | Open file, update wifi SSID and password, compile and run -------------------------------------------------------------------------------- /arduino/botnet-fishbowl.ino: -------------------------------------------------------------------------------- 1 | //The Game of Life, also known simply as Life, is a cellular automaton 2 | //devised by the British mathematician John Horton Conway in 1970. 3 | // https://en.wikipedia.org/wiki/Conway's_Game_of_Life 4 | 5 | #include 6 | #include 7 | 8 | const char* ssid = "WiFi SSID"; 9 | const char* password = "WiFi Password"; 10 | 11 | int status = WL_IDLE_STATUS; 12 | 13 | WiFiServer wifiServer(6666); 14 | 15 | //#define GRIDX 80 16 | //#define GRIDY 60 17 | //#define CELLXY 4 18 | 19 | #define GRIDX 160 20 | #define GRIDY 120 21 | #define CELLXY 2 22 | 23 | #define GEN_DELAY 0 24 | 25 | //Current grid 26 | uint8_t grid[GRIDX][GRIDY]; 27 | 28 | //The new grid for the next generation 29 | uint8_t newgrid[GRIDX][GRIDY]; 30 | 31 | uint16_t genCount = 0; 32 | 33 | void setup() { 34 | 35 | //Set up the display 36 | M5.begin(); 37 | M5.Power.begin(); 38 | // M5.Lcd.setRotation(3); 39 | M5.Lcd.fillScreen(TFT_BLACK); 40 | M5.Lcd.setTextSize(1); 41 | M5.Lcd.setTextColor(TFT_WHITE); 42 | M5.Lcd.setCursor(0, 0); 43 | Serial.begin(9600); 44 | delay(10); 45 | 46 | // We start by connecting to a WiFi network 47 | 48 | Serial.println(); 49 | Serial.println(); 50 | Serial.print("Connecting to "); 51 | Serial.println(ssid); 52 | 53 | WiFi.begin(ssid, password); 54 | 55 | while (WiFi.status() != WL_CONNECTED) { 56 | delay(500); 57 | Serial.print("."); 58 | } 59 | 60 | Serial.println(""); 61 | Serial.println("WiFi connected"); 62 | Serial.println("IP address: "); 63 | Serial.println(WiFi.localIP()); 64 | wifiServer.begin(); 65 | 66 | } 67 | 68 | void loop() { 69 | delay(1000); 70 | 71 | M5.Lcd.fillScreen(TFT_BLACK); 72 | 73 | initGrid(); 74 | 75 | drawGrid(); 76 | 77 | //Compute generations 78 | while (true) 79 | { 80 | WiFiClient client = wifiServer.available(); 81 | if (client) { 82 | while (client.connected()) { 83 | while (client.available() > 0) { 84 | char c = client.read(); 85 | Serial.write(c); 86 | } 87 | reseedGrid(); 88 | delay(10); 89 | } 90 | client.stop(); 91 | Serial.println("Client disconnected"); 92 | } 93 | computeCA(); 94 | drawGrid(); 95 | delay(GEN_DELAY); 96 | for (int16_t x = 1; x < GRIDX - 1; x++) { 97 | for (int16_t y = 1; y < GRIDY - 1; y++) { 98 | grid[x][y] = newgrid[x][y]; 99 | } 100 | } 101 | 102 | } 103 | } 104 | 105 | //Draws the grid on the display 106 | void drawGrid(void) { 107 | 108 | uint16_t color = TFT_WHITE; 109 | for (int16_t x = 1; x < GRIDX - 1; x++) { 110 | for (int16_t y = 1; y < GRIDY - 1; y++) { 111 | if ((grid[x][y]) != (newgrid[x][y])) { 112 | if (newgrid[x][y] == 1) color = 0x0F00; //random(0xFFFF); 113 | else color = 0; 114 | M5.Lcd.fillRect(CELLXY * x, CELLXY * y, CELLXY, CELLXY, color); 115 | } 116 | } 117 | } 118 | } 119 | 120 | //Initialise Grid 121 | void initGrid(void) { 122 | for (int16_t x = 0; x < GRIDX; x++) { 123 | for (int16_t y = 0; y < GRIDY; y++) { 124 | newgrid[x][y] = 0; 125 | 126 | if (x == 0 || x == GRIDX - 1 || y == 0 || y == GRIDY - 1) { 127 | grid[x][y] = 0; 128 | } 129 | else { 130 | if (random(3) == 1) 131 | grid[x][y] = 1; 132 | else 133 | grid[x][y] = 0; 134 | } 135 | 136 | } 137 | } 138 | } 139 | 140 | void reseedGrid(void) { 141 | for (int16_t x = 0; x < GRIDX; x++) { 142 | for (int16_t y = 0; y < GRIDY; y++) { 143 | newgrid[x][y] = 0; 144 | 145 | if (x == 0 || x == GRIDX - 1 || y == 0 || y == GRIDY - 1) { 146 | grid[x][y] = 0; 147 | } 148 | else { 149 | //10% chance of reseed 150 | if (random(100) <= 10) 151 | grid[x][y] = 1; 152 | else 153 | grid[x][y] = 0; 154 | } 155 | 156 | } 157 | } 158 | } 159 | 160 | //Compute the CA. Basically everything related to CA starts here 161 | void computeCA() { 162 | for (int16_t x = 1; x < GRIDX; x++) { 163 | for (int16_t y = 1; y < GRIDY; y++) { 164 | int neighbors = getNumberOfNeighbors(x, y); 165 | if (grid[x][y] == 1 && (neighbors == 2 || neighbors == 3 )) 166 | { 167 | newgrid[x][y] = 1; 168 | } 169 | else if (grid[x][y] == 1) newgrid[x][y] = 0; 170 | if (grid[x][y] == 0 && (neighbors == 3)) 171 | { 172 | newgrid[x][y] = 1; 173 | } 174 | else if (grid[x][y] == 0) newgrid[x][y] = 0; 175 | } 176 | } 177 | } 178 | 179 | // Check the Moore neighborhood 180 | int getNumberOfNeighbors(int x, int y) { 181 | return grid[x - 1][y] + grid[x - 1][y - 1] + grid[x][y - 1] + grid[x + 1][y - 1] + grid[x + 1][y] + grid[x + 1][y + 1] + grid[x][y + 1] + grid[x - 1][y + 1]; 182 | } 183 | 184 | /* 185 | The MIT License (MIT) 186 | 187 | Copyright (c) 2016 RuntimeProjects.com 188 | 189 | Permission is hereby granted, free of charge, to any person obtaining a copy 190 | of this software and associated documentation files (the "Software"), to deal 191 | in the Software without restriction, including without limitation the rights 192 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 193 | copies of the Software, and to permit persons to whom the Software is 194 | furnished to do so, subject to the following conditions: 195 | 196 | The above copyright notice and this permission notice shall be included in all 197 | copies or substantial portions of the Software. 198 | 199 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 200 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 201 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 202 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 203 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 204 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 205 | SOFTWARE. 206 | */ 207 | -------------------------------------------------------------------------------- /golang/README.md: -------------------------------------------------------------------------------- 1 | go get the dependencies 2 | 3 | go build ./botnet-fishbowl.go -------------------------------------------------------------------------------- /golang/botnet-fishbowl.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // The MIT License (MIT) 4 | // 5 | // Copyright (c) 2015-2016 Martin Lindhe 6 | // Copyright (c) 2016 Hajime Hoshi 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 24 | // DEALINGS IN THE SOFTWARE. 25 | 26 | import ( 27 | "encoding/binary" 28 | "fmt" 29 | "log" 30 | "math/rand" 31 | "net" 32 | "os" 33 | "time" 34 | 35 | "github.com/hajimehoshi/ebiten/v2" 36 | ) 37 | 38 | var ( 39 | globalConn net.Listener 40 | ) 41 | 42 | func init() { 43 | rand.Seed(time.Now().UnixNano()) 44 | } 45 | 46 | // World represents the game state. 47 | type World struct { 48 | area []bool 49 | width int 50 | height int 51 | } 52 | 53 | // NewWorld creates a new world. 54 | func NewWorld(width, height int, maxInitLiveCells int) *World { 55 | w := &World{ 56 | area: make([]bool, width*height), 57 | width: width, 58 | height: height, 59 | } 60 | w.init(maxInitLiveCells) 61 | return w 62 | } 63 | 64 | // init inits world with a random state. 65 | func (w *World) init(maxLiveCells int) { 66 | for i := 0; i < maxLiveCells; i++ { 67 | x := rand.Intn(w.width) 68 | y := rand.Intn(w.height) 69 | w.area[y*w.width+x] = true 70 | } 71 | } 72 | 73 | // Update game state by one tick. 74 | func (w *World) Update() { 75 | width := w.width 76 | height := w.height 77 | next := make([]bool, width*height) 78 | for y := 0; y < height; y++ { 79 | for x := 0; x < width; x++ { 80 | pop := neighbourCount(w.area, width, height, x, y) 81 | switch { 82 | case pop < 2: 83 | // rule 1. Any live cell with fewer than two live neighbours 84 | // dies, as if caused by under-population. 85 | next[y*width+x] = false 86 | 87 | case (pop == 2 || pop == 3) && w.area[y*width+x]: 88 | // rule 2. Any live cell with two or three live neighbours 89 | // lives on to the next generation. 90 | next[y*width+x] = true 91 | 92 | case pop > 3: 93 | // rule 3. Any live cell with more than three live neighbours 94 | // dies, as if by over-population. 95 | next[y*width+x] = false 96 | 97 | case pop == 3: 98 | // rule 4. Any dead cell with exactly three live neighbours 99 | // becomes a live cell, as if by reproduction. 100 | next[y*width+x] = true 101 | } 102 | } 103 | } 104 | w.area = next 105 | } 106 | 107 | // Draw paints current game state. 108 | func (w *World) Draw(pix []byte) { 109 | for i, v := range w.area { 110 | if v { 111 | pix[4*i] = 0x00 112 | pix[4*i+1] = 0xff 113 | pix[4*i+2] = 0x00 114 | pix[4*i+3] = 0xff 115 | } else { 116 | pix[4*i] = 0 117 | pix[4*i+1] = 0 118 | pix[4*i+2] = 0 119 | pix[4*i+3] = 0 120 | } 121 | } 122 | } 123 | 124 | func max(a, b int) int { 125 | if a < b { 126 | return b 127 | } 128 | return a 129 | } 130 | 131 | func min(a, b int) int { 132 | if a < b { 133 | return a 134 | } 135 | return b 136 | } 137 | 138 | // neighbourCount calculates the Moore neighborhood of (x, y). 139 | func neighbourCount(a []bool, width, height, x, y int) int { 140 | c := 0 141 | for j := -1; j <= 1; j++ { 142 | for i := -1; i <= 1; i++ { 143 | if i == 0 && j == 0 { 144 | continue 145 | } 146 | x2 := x + i 147 | y2 := y + j 148 | if x2 < 0 || y2 < 0 || width <= x2 || height <= y2 { 149 | continue 150 | } 151 | if a[y2*width+x2] { 152 | c++ 153 | } 154 | } 155 | } 156 | return c 157 | } 158 | 159 | const ( 160 | screenWidth = 320 161 | screenHeight = 240 162 | 163 | connHost = "0.0.0.0" 164 | connPort = "6666" 165 | connType = "tcp" 166 | ) 167 | 168 | type Game struct { 169 | world *World 170 | pixels []byte 171 | } 172 | 173 | func (w *World) listenForBots() { 174 | conn, err := globalConn.Accept() 175 | if err != nil { 176 | fmt.Println("Error accepting: ", err.Error()) 177 | } 178 | // Handle connections in a new goroutine. 179 | go w.handleRequest(conn) 180 | } 181 | 182 | func (w *World) handleRequest(conn net.Conn) { 183 | // Make a buffer to hold incoming data. 184 | buf := make([]byte, 8) 185 | // Read the incoming connection into the buffer. 186 | _, err := conn.Read(buf) 187 | if err != nil { 188 | fmt.Println("Error reading:", err.Error()) 189 | } 190 | // Send a response back to person contacting us. 191 | conn.Write([]byte("Message received. Thanks for the entertainment")) 192 | // Close the connection when you're done with it. 193 | conn.Close() 194 | 195 | rand.Seed(int64(binary.LittleEndian.Uint64(buf))) 196 | for i := 0; i < int((screenWidth*screenHeight)/100); i++ { 197 | x := rand.Intn(w.width) 198 | y := rand.Intn(w.height) 199 | w.area[y*w.width+x] = true 200 | } 201 | 202 | } 203 | 204 | func (g *Game) Update() error { 205 | // Listen for an incoming connection. 206 | go g.world.listenForBots() 207 | g.world.Update() 208 | return nil 209 | } 210 | 211 | func (g *Game) Draw(screen *ebiten.Image) { 212 | if g.pixels == nil { 213 | g.pixels = make([]byte, screenWidth*screenHeight*4) 214 | } 215 | g.world.Draw(g.pixels) 216 | screen.ReplacePixels(g.pixels) 217 | } 218 | 219 | func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) { 220 | return screenWidth, screenHeight 221 | } 222 | 223 | func main() { 224 | // Listen for incoming connections. 225 | l, lerr := net.Listen(connType, connHost+":"+connPort) 226 | if lerr != nil { 227 | fmt.Println("Error listening:", lerr.Error()) 228 | os.Exit(1) 229 | } 230 | // Close the listener when the application closes. 231 | defer l.Close() 232 | globalConn = l 233 | 234 | g := &Game{ 235 | world: NewWorld(screenWidth, screenHeight, int((screenWidth*screenHeight)/10)), 236 | } 237 | 238 | ebiten.SetWindowSize(screenWidth*2, screenHeight*2) 239 | ebiten.SetFullscreen(true) 240 | //ebiten.SetWindowTitle("Game of Life (Ebiten Demo)") 241 | if err := ebiten.RunGame(g); err != nil { 242 | log.Fatal(err) 243 | } 244 | } 245 | -------------------------------------------------------------------------------- /golang/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/xen0bit/botnet-fishbowl 2 | 3 | go 1.15 4 | 5 | require ( 6 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20201108214237-06ea97f0c265 // indirect 7 | github.com/hajimehoshi/ebiten/v2 v2.0.3 // indirect 8 | golang.org/x/exp v0.0.0-20210126221216-84987778548c // indirect 9 | golang.org/x/image v0.0.0-20201208152932-35266b937fa6 // indirect 10 | golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c // indirect 11 | ) 12 | -------------------------------------------------------------------------------- /golang/go.sum: -------------------------------------------------------------------------------- 1 | dmitri.shuralyov.com/gpu/mtl v0.0.0-20201218220906-28db891af037/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= 2 | github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= 3 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 4 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200707082815-5321531c36a2 h1:Ac1OEHHkbAZ6EUnJahF0GKcU0FjPc/V8F1DvjhKngFE= 5 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200707082815-5321531c36a2/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 6 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20201108214237-06ea97f0c265 h1:BcbKYUZo/TKPsiSh7LymK3p+TNAJJW3OfGO/21sBbiA= 7 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20201108214237-06ea97f0c265/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 8 | github.com/gofrs/flock v0.8.0/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= 9 | github.com/hajimehoshi/bitmapfont/v2 v2.1.0/go.mod h1:2BnYrkTQGThpr/CY6LorYtt/zEPNzvE/ND69CRTaHMs= 10 | github.com/hajimehoshi/ebiten v1.12.6 h1:KCTUGIgpenGkwA4wV+5PlKvh2L4T9tbSxNzV46OeDgE= 11 | github.com/hajimehoshi/ebiten/v2 v2.0.3 h1:hlHTz2kIMRG0FO8RcuF70kE49W7kEz6ea7io275XF+w= 12 | github.com/hajimehoshi/ebiten/v2 v2.0.3/go.mod h1:AbHP/SS226aFTex/izULVwW0D2AuGyqC4AVwilmRjOg= 13 | github.com/hajimehoshi/file2byteslice v0.0.0-20200812174855-0e5e8a80490e/go.mod h1:CqqAHp7Dk/AqQiwuhV1yT2334qbA/tFWQW0MD2dGqUE= 14 | github.com/hajimehoshi/go-mp3 v0.3.1/go.mod h1:qMJj/CSDxx6CGHiZeCgbiq2DSUkbK0UbtXShQcnfyMM= 15 | github.com/hajimehoshi/oto v0.6.1/go.mod h1:0QXGEkbuJRohbJaxr7ZQSxnju7hEhseiPx2hrh6raOI= 16 | github.com/hajimehoshi/oto v0.6.8/go.mod h1:0QXGEkbuJRohbJaxr7ZQSxnju7hEhseiPx2hrh6raOI= 17 | github.com/jakecoffman/cp v1.0.0/go.mod h1:JjY/Fp6d8E1CHnu74gWNnU0+b9VzEdUVPoJxg2PsTQg= 18 | github.com/jfreymuth/oggvorbis v1.0.1/go.mod h1:NqS+K+UXKje0FUYUPosyQ+XTVvjmVjps1aEZH1sumIk= 19 | github.com/jfreymuth/vorbis v1.0.0/go.mod h1:8zy3lUAm9K/rJJk223RKy6vjCZTWC61NA2QD06bfOE0= 20 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 21 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 22 | github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= 23 | github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA= 24 | github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 25 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 26 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 27 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 28 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 29 | golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 30 | golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56 h1:estk1glOnSVeJ9tdEZZc5mAMDZk5lNJNyJ6DvrBkTEU= 31 | golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= 32 | golang.org/x/exp v0.0.0-20210126221216-84987778548c h1:sWZb7hc7UoMhB5/VYk5+nsHuiHq8J5l0osfBYs9C3gw= 33 | golang.org/x/exp v0.0.0-20210126221216-84987778548c/go.mod h1:I6l2HNBLBZEcrOoCpyKLdY2lHoRZ8lI4x60KMCQDft4= 34 | golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= 35 | golang.org/x/image v0.0.0-20190703141733-d6a02ce849c9/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 36 | golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 37 | golang.org/x/image v0.0.0-20200927104501-e162460cd6b5 h1:QelT11PB4FXiDEXucrfNckHoFxwt8USGY1ajP1ZF5lM= 38 | golang.org/x/image v0.0.0-20200927104501-e162460cd6b5/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 39 | golang.org/x/image v0.0.0-20201208152932-35266b937fa6 h1:nfeHNc1nAqecKCy2FCy4HY+soOOe5sDLJ/gZLbx6GYI= 40 | golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 41 | golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= 42 | golang.org/x/mobile v0.0.0-20190415191353-3e0bab5405d6/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= 43 | golang.org/x/mobile v0.0.0-20200801112145-973feb4309de h1:OVJ6QQUBAesB8CZijKDSsXX7xYVtUhrkY0gwMfbi4p4= 44 | golang.org/x/mobile v0.0.0-20200801112145-973feb4309de/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4= 45 | golang.org/x/mobile v0.0.0-20201217150744-e6ae53a27f4f h1:kgfVkAEEQXXQ0qc6dH7n6y37NAYmTFmz0YRwrRjgxKw= 46 | golang.org/x/mobile v0.0.0-20201217150744-e6ae53a27f4f/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4= 47 | golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= 48 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 49 | golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 50 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 51 | golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 52 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 53 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 54 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 55 | golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 56 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 57 | golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 58 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 59 | golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 60 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 61 | golang.org/x/sys v0.0.0-20190429190828-d89cdac9e872/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 62 | golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 63 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 64 | golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634 h1:bNEHhJCnrwMKNMmOx3yAynp5vs5/gRy+XWFtZFu7NBM= 65 | golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 66 | golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk= 67 | golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 68 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 69 | golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 70 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 71 | golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 72 | golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 73 | golang.org/x/tools v0.0.0-20201009162240-fcf82128ed91/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= 74 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 75 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 76 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 77 | gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 78 | -------------------------------------------------------------------------------- /micropython/README.md: -------------------------------------------------------------------------------- 1 | Really slow, networking not working entirely, might fix this one day. -------------------------------------------------------------------------------- /micropython/botnet-fishbowl.mpy: -------------------------------------------------------------------------------- 1 | from m5stack import * 2 | from m5ui import * 3 | from uiflow import * 4 | import usocket as socket 5 | import network, machine 6 | import wifiCfg 7 | from random import randint 8 | 9 | lcd.clear() 10 | 11 | wlan_sta = network.WLAN(network.STA_IF); 12 | 13 | #Initialise the screen 14 | #Block size controls pretty much all math beneath it. Smaller numbers may result in OOM errors 15 | block_size = 5 16 | xmax = int(320/block_size) #Width of screen in pixels 17 | ymax = int(240/block_size) #Height of screen in pixels 18 | 19 | def evolve_cell(alive, neighbours): 20 | return neighbours == 3 or (alive and neighbours == 2) 21 | 22 | def count_neighbours(grid, position): 23 | x,y = position 24 | neighbour_cells = [(x - 1, y - 1), (x - 1, y + 0), (x - 1, y + 1), 25 | (x + 0, y - 1), (x + 0, y + 1), 26 | (x + 1, y - 1), (x + 1, y + 0), (x + 1, y + 1)] 27 | count = 0 28 | for x,y in neighbour_cells: 29 | if x >= 0 and y >= 0: 30 | try: 31 | count += grid[x][y] 32 | except: 33 | pass 34 | return count 35 | 36 | def make_empty_grid(x, y): 37 | grid = [] 38 | for r in range(x): 39 | row = [] 40 | for c in range(y): 41 | row.append(0) 42 | grid.append(row) 43 | return grid 44 | 45 | def make_random_grid(x, y): 46 | grid = [] 47 | for r in range(x): 48 | row = [] 49 | for c in range(y): 50 | temp = randint(0,100) 51 | if(temp < 10): 52 | row.append(1) 53 | else: 54 | row.append(0) 55 | #row.append(randint(0,1)) 56 | grid.append(row) 57 | return grid 58 | 59 | def evolve(grid): 60 | x = len(grid) 61 | y = len(grid[0]) 62 | new_grid = make_empty_grid(x, y) 63 | for r in range(x): 64 | for c in range(y): 65 | cell = grid[r][c] 66 | neighbours = count_neighbours(grid, (r, c)) 67 | new_grid[r][c] = 1 if evolve_cell(cell, neighbours) else 0 68 | return new_grid 69 | 70 | alive_color = 0x00FF00 71 | BLACK = 0x000000 72 | 73 | def drawRect(x1, y1, x2, y2, color): 74 | for x in range(x1, x2): 75 | for y in range(y1, y2): 76 | lcd.pixel(x, y, color) 77 | 78 | 79 | def draw_block(x, y, color): 80 | x *= block_size 81 | y *= block_size 82 | #print(center_point) 83 | #lcd.fill(color) 84 | #lcd.rect(x-block_size, y-block_size, x, y, color=color, fillcolor=color) 85 | #lcd.pixel(x, y, color) 86 | drawRect(x-block_size, y-block_size, x, y, color) 87 | 88 | 89 | def main(): 90 | wifiCfg.doConnect('Wifi SSID', 'Wifi Password') 91 | wifiCfg.autoConnect(lcdShow=True) 92 | if wlan_sta.isconnected(): 93 | lcd.println("Connected! \r\nNetwork config:\r\n"+wlan_sta.ifconfig()[0]+', '+wlan_sta.ifconfig()[3]) 94 | addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1] 95 | #serversocket.bind(addr, 80)) 96 | serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 97 | serversocket.bind(addr) 98 | serversocket.listen(5) 99 | lcd.println('listening on'+str(addr)) 100 | # while 1: 101 | # #accept connections from outside 102 | # (clientsocket, address) = serversocket.accept() 103 | # data = clientsocket.recv(1024) 104 | # clientsocket.close() 105 | # lcd.clear() 106 | # for i in data: 107 | # lcd.println(data) 108 | 109 | cell_number = 0 110 | world = make_random_grid(xmax, ymax) 111 | lcd.set_bg(BLACK) 112 | while True: 113 | #for i in range(200): 114 | for x in range(xmax): 115 | for y in range(ymax): 116 | alive = world[x][y] 117 | cell_number += 1 118 | #cell_color = alive_color if alive else BLACK 119 | if alive: 120 | draw_block(x, y, alive_color) 121 | #_thread.start_new_thread(draw_block, (x, y, alive_color)) 122 | world = evolve(world) 123 | lcd.clear() 124 | cell_number = 0 125 | #sleep(0.1) 126 | 127 | main() 128 | --------------------------------------------------------------------------------