diff --git a/Games/Life's_Mossaic/.gitignore b/Games/Life's_Mossaic/.gitignore new file mode 100644 index 0000000000..f83526d133 --- /dev/null +++ b/Games/Life's_Mossaic/.gitignore @@ -0,0 +1 @@ +**/node_modules/ \ No newline at end of file diff --git a/Games/Life's_Mossaic/README.md b/Games/Life's_Mossaic/README.md new file mode 100644 index 0000000000..75401690b1 --- /dev/null +++ b/Games/Life's_Mossaic/README.md @@ -0,0 +1,207 @@ +
+

Life's Mosaic

+

A cellular automaton devised by British mathematician John Horton Conway in 1970.

+
+ +--- +## โœจ What is it? + +Life's Mosaic, or simply "Life," is a cellular automaton devised by British mathematician John Horton Conway in 1970. It is a zero-player game, meaning its evolution is determined by its initial state, requiring no further input. Players interact with the game by creating an initial configuration and observing how it evolves. The game is Turing complete and can simulate a universal constructor or any other Turing machine. + +--- + +## ๐ŸŒŒ The Universe + +The universe of the Game of Life is an infinite, two-dimensional orthogonal grid of square cells. Each cell is in one of two possible states: `ALIVE` or `DEAD`. Every cell interacts with its eight neighbors, which are the cells that are horizontally, vertically, or diagonally adjacent. + +--- +## ๐Ÿ“œ The Rules + +1. Any live cell with fewer than two live neighbors dies, as if by **underpopulation**. +2. Any live cell with two or three live neighbors lives on to the next generation. +3. Any live cell with more than three live neighbors dies, as if by **overpopulation**. +4. Any dead cell with exactly three live neighbors becomes a live cell, as if by **reproduction**. + +The first generation is created by applying the above rules simultaneously to every cell in the seed, alive or dead; births and deaths occur simultaneously, and the discrete moment at which this happens is sometimes called a tick. Each generation is a pure function of the preceding one. + +--- + +## ๐ŸŽฎ The Game + +### ๐Ÿ–ผ๏ธ The Canvas / Grid + +![Game Grid](data/game-images/Game-Grid.png) + +| Buttons | What they do | +| --- | --- | +| โ–ถ๏ธ | Starts the animation after you've set the initial pattern | +| โธ๏ธ | Pauses the animation | +| โฉ | Increases the speed of the animation | +| โช | Decreases the speed of the animation | +| `Clear` | Clears the grid on click, only if the game is not animating at that moment | +| `Random` | Randomly initializes the grid with initial randomness as 20% | + + +### โš™๏ธ The Settings + +| Settings | What are they for? | +| --- | --- | +| `Gridlines` | Toggles visibility of the gridlines | +| `Warp on Edges` | Warps the patterns across the edges - Initially set as true | +| `Randomness` | Allows you to set custom randomness percent for random initialization | + + +### ๐ŸŽจ The Themes + +| Themes | The Colors | +| --- | --- | +| Blue (default) | ![#0f045a](https://placehold.co/15x15/0f045a/0f045a.png) ![#7582b2](https://placehold.co/15x15/7582b2/7582b2.png) ![#036c96](https://placehold.co/15x15/036c96/036c96.png) ![#ebf2ff](https://placehold.co/15x15/ebf2ff/ebf2ff.png) ![#352a7e](https://placehold.co/15x15/352a7e/352a7e.png) ![#101536](https://placehold.co/15x15/101536/101536.png) ![#080126](https://placehold.co/15x15/080126/080126.png) ![#c6cede](https://placehold.co/15x15/c6cede/c6cede.png) ![#00246B](https://placehold.co/15x15/00246B/00246B.png) ![#CADCFC](https://placehold.co/15x15/CADCFC/CADCFC.png) | +| Red | ![#5a0404](https://placehold.co/15x15/5a0404/5a0404.png) ![#B27575](https://placehold.co/15x15/B27575/B27575.png) ![#960320](https://placehold.co/15x15/960320/960320.png) ![#FFEBEB](https://placehold.co/15x15/FFEBEB/FFEBEB.png) ![#7E2A37](https://placehold.co/15x15/7E2A37/7E2A37.png) ![#361015](https://placehold.co/15x15/361015/361015.png) ![#260106](https://placehold.co/15x15/260106/260106.png) ![#DEC6C6](https://placehold.co/15x15/DEC6C6/DEC6C6.png) ![#6b0000](https://placehold.co/15x15/6b0000/6b0000.png) ![#fccaca](https://placehold.co/15x15/fccaca/fccaca.png) | +| Green | ![#045a1e](https://placehold.co/15x15/045a1e/045a1e.png) ![#75B289](https://placehold.co/15x15/75B289/75B289.png) ![#03962f](https://placehold.co/15x15/03962f/03962f.png) ![#EBFFEF](https://placehold.co/15x15/EBFFEF/EBFFEF.png) ![#2A7E4D](https://placehold.co/15x15/2A7E4D/2A7E4D.png) ![#10361C](https://placehold.co/15x15/10361C/10361C.png) ![#01260B](https://placehold.co/15x15/01260B/01260B.png) ![#C6DECC](https://placehold.co/15x15/C6DECC/C6DECC.png) ![#006b2b](https://placehold.co/15x15/006b2b/006b2b.png) ![#cafcdd](https://placehold.co/15x15/cafcdd/cafcdd.png) | +| Purple | ![#5a045a](https://placehold.co/15x15/5a045a/5a045a.png) ![#B275B2](https://placehold.co/15x15/B275B2/B275B2.png) ![#960396](https://placehold.co/15x15/960396/960396.png) ![#FFEBFF](https://placehold.co/15x15/FFEBFF/FFEBFF.png) ![#7E2A7E](https://placehold.co/15x15/7E2A7E/7E2A7E.png) ![#361036](https://placehold.co/15x15/361036/361036.png) ![#260126](https://placehold.co/15x15/260126/260126.png) ![#DEC6DE](https://placehold.co/15x15/DEC6DE/DEC6DE.png) ![#6b006b](https://placehold.co/15x15/6b006b/6b006b.png) ![#fcafcf](https://placehold.co/15x15/fcafcf/fcafcf.png) | +| Dark Cyan | ![#045a5a](https://placehold.co/15x15/045a5a/045a5a.png) ![#75B2B2](https://placehold.co/15x15/75B2B2/75B2B2.png) ![#039696](https://placehold.co/15x15/039696/039696.png) ![#EBFFFF](https://placehold.co/15x15/EBFFFF/EBFFFF.png) ![#2A7E7E](https://placehold.co/15x15/2A7E7E/2A7E7E.png) ![#103636](https://placehold.co/15x15/103636/103636.png) ![#012626](https://placehold.co/15x15/012626/012626.png) ![#C6DEDE](https://placehold.co/15x15/C6DEDE/C6DEDE.png) ![#006b6b](https://placehold.co/15x15/006b6b/006b6b.png) ![#cafcfc](https://placehold.co/15x15/cafcfc/cafcfc.png) | +| Dark Neon | ![#d0ff00](https://placehold.co/15x15/d0ff00/d0ff00.png) ![#00cc26](https://placehold.co/15x15/00cc26/00cc26.png) ![#00b81b](https://placehold.co/15x15/00b81b/00b81b.png) ![#004640](https://placehold.co/15x15/004640/004640.png) ![#fc0101](https://placehold.co/15x15/fc0101/fc0101.png) ![#000000](https://placehold.co/15x15/000000/000000.png) ![#002628](https://placehold.co/15x15/002628/002628.png) ![#000525](https://placehold.co/15x15/000525/000525.png) ![#9800f5](https://placehold.co/15x15/9800f5/9800f5.png) ![#80ffff](https://placehold.co/15x15/80ffff/80ffff.png) | + + +### โณ History + +Stores history of patterns that user has played with, up to 5 recent patterns. + +--- + +## ๐Ÿ”ฎ The Presets + +### Glider + +The glider is the smallest, most common, and first-discovered spaceship in Game of Life. It travels diagonally across the grid. Gliders are important because they are easily produced, can be collided with each other to form more complicated patterns, and can be used to transmit information over long distances. + +
+ Small Glider + +
+ +### Big Glider + +The big glider was found by Dean Hickerson in December 1989 and was the first known diagonal spaceship other than the glider. Two gliders can be temporarily seen at the front of the ship; these do not stay gliders but still move like them. + +
+ Big Glider + +
+ +### Gosper Glider Gun + +The Gosper glider gun is the first known gun, and indeed the first known finite pattern with unbounded growth, found by Bill Gosper in November 1970. It consists of two queen bee shuttles stabilized by two blocks. + +
+ Gosper Glider Gun + +
+ + +### Pulsar + +The pulsar is a period-3 oscillator, meaning it returns to its initial state after three generations. Itโ€™s a symmetric pattern and one of the most recognized oscillators in the Game of Life. + +
+ Pulsar + +
+ +### Circle of Fire + +This term isnโ€™t standard in the Game of Life nomenclature but could refer to a specific type of oscillator or a similar repeating pattern that creates a visual effect resembling a circle of fire. + +
+ Circle-of-Fire + +
+ +### Quadpole + +The quadpole is the eighth most common oscillator in Achim Flammenkamp's census, being less common than the bipole but more common than the great on-off. It is the eighth most common oscillator on Adam P. Goucher's Catagolue. + +
+ Quadpole + +
+ +### Spider + +Spider is a c/5 orthogonal spaceship that was discovered by David Bell on April 14, 1997. It is the smallest known c/5 orthogonal spaceship. Its side sparks have proven to be very useful in constructing puffers and rakes. + +
+ Spider + +
+ +### More Configurations + +Explore more patterns at [ConwayLife Patterns](https://conwaylife.com/wiki/Category:Patterns). + +--- + +## ๐Ÿ“š Resources + +### Spark your interest + +- [The Game of Life | John Conway | TEDxDanubia](https://www.youtube.com/watch?v=R9Plq-D1gEk) +- [Conway's Game of Life Explained](https://youtu.be/C2vgICfQawE?si=yWqN0BOSBOMaujkI) + +### Try playing it here + +- [Play Game of Life](https://playgameoflife.com/) +- [Conway Life](https://conwaylife.com/) + + +
+

Life's Mosaic offers a unique way to explore the unpredictable beauty of life itself.

+
+ + +
+

Open Source Programs

+
+ + This project is part of GirlScript Summer of Code. We welcome contributions from the community to help enhance gameoflife. + +![gssoc](https://github.com/d1vyadharsh1n1/Flipkart_Clone/assets/146218077/dd4ffa29-2d52-47ad-9967-d0d6f8aff717) + +
+ + +
+

Code of Conduct

+
+ +Please note that this project is released with a [Contributor Code of Conduct](./CODE_OF_CONDUCT.md). By participating in this project you agree to abide by its terms. + +
+ + +
+

License

+
+ +This project is licensed under the [GPL-3.0 License](LICENSE.md). + +
+ +## Contact Us +
+https://www.linkedin.com/in/shriharimagar/ +
+ +
+ +
+

Contributors

+
+ +Thank you for contributing to our project! Your help is greatly appreciated in making gameoflife even better. ๐Ÿ˜Š + +
+ + + +
\ No newline at end of file diff --git a/Games/Life's_Mossaic/animation.js b/Games/Life's_Mossaic/animation.js new file mode 100644 index 0000000000..9fbf98652b --- /dev/null +++ b/Games/Life's_Mossaic/animation.js @@ -0,0 +1,40 @@ +// used to animate side navbar +gsap.from(".game-settings .sidenav .animate", { + duration: 1, + x: -500, + ease: "power1.inOut", + stagger: 0.2 +}); +document.getElementById("toggleButton").addEventListener("click", function animateNav() { + gsap.set(".game-settings .sidenav .animate", { x: -500 }); + + gsap.to(".game-settings .sidenav .animate", { + duration: 1, + x: 0, + ease: "power1.inOut", + stagger: 0.3 + }); +}); +// used to animate the heading +gsap.from(".heading", { + duration: 1, + y: -500, + ease: "power1.inOut", + stagger: 0.2, + onComplete: function() { + // After the initial animation, start the yoyo bouncing effect + gsap.to(".heading", { + duration: 1, + y: -5, + ease: "power1.inOut", + yoyo: true, + repeat: -1 + });} +}); +// used to animate the grid +gsap.from(".grid-container", { + duration: 1, + x: 1000, + ease: "power1.inOut", + stagger: 0.2 +}); diff --git a/Games/Life's_Mossaic/data/game-images/Big-Glider.png b/Games/Life's_Mossaic/data/game-images/Big-Glider.png new file mode 100644 index 0000000000..bbc4d29f6d Binary files /dev/null and b/Games/Life's_Mossaic/data/game-images/Big-Glider.png differ diff --git a/Games/Life's_Mossaic/data/game-images/Circle-of-Fire.png b/Games/Life's_Mossaic/data/game-images/Circle-of-Fire.png new file mode 100644 index 0000000000..61cfdbbde1 Binary files /dev/null and b/Games/Life's_Mossaic/data/game-images/Circle-of-Fire.png differ diff --git a/Games/Life's_Mossaic/data/game-images/Game-Grid.png b/Games/Life's_Mossaic/data/game-images/Game-Grid.png new file mode 100644 index 0000000000..12f4e44a55 Binary files /dev/null and b/Games/Life's_Mossaic/data/game-images/Game-Grid.png differ diff --git a/Games/Life's_Mossaic/data/game-images/Game-Sidebar.png b/Games/Life's_Mossaic/data/game-images/Game-Sidebar.png new file mode 100644 index 0000000000..5e07dec691 Binary files /dev/null and b/Games/Life's_Mossaic/data/game-images/Game-Sidebar.png differ diff --git a/Games/Life's_Mossaic/data/game-images/Gosper-Glider-Gun.png b/Games/Life's_Mossaic/data/game-images/Gosper-Glider-Gun.png new file mode 100644 index 0000000000..ac5d4d3d25 Binary files /dev/null and b/Games/Life's_Mossaic/data/game-images/Gosper-Glider-Gun.png differ diff --git a/Games/Life's_Mossaic/data/game-images/Pulsar.png b/Games/Life's_Mossaic/data/game-images/Pulsar.png new file mode 100644 index 0000000000..6e10c15898 Binary files /dev/null and b/Games/Life's_Mossaic/data/game-images/Pulsar.png differ diff --git a/Games/Life's_Mossaic/data/game-images/Quadpole.png b/Games/Life's_Mossaic/data/game-images/Quadpole.png new file mode 100644 index 0000000000..e1d6e5266b Binary files /dev/null and b/Games/Life's_Mossaic/data/game-images/Quadpole.png differ diff --git a/Games/Life's_Mossaic/data/game-images/Small-Glider.png b/Games/Life's_Mossaic/data/game-images/Small-Glider.png new file mode 100644 index 0000000000..32ddd31a11 Binary files /dev/null and b/Games/Life's_Mossaic/data/game-images/Small-Glider.png differ diff --git a/Games/Life's_Mossaic/data/game-images/Spider.png b/Games/Life's_Mossaic/data/game-images/Spider.png new file mode 100644 index 0000000000..6763d344d0 Binary files /dev/null and b/Games/Life's_Mossaic/data/game-images/Spider.png differ diff --git a/Games/Life's_Mossaic/data/presets.json b/Games/Life's_Mossaic/data/presets.json new file mode 100644 index 0000000000..172d6c56ca --- /dev/null +++ b/Games/Life's_Mossaic/data/presets.json @@ -0,0 +1,338 @@ +{ + "GliderGun": [ + [5, 1], + [6, 1], + [5, 2], + [6, 2], + [5, 11], + [6, 11], + [7, 11], + [4, 12], + [8, 12], + [3, 13], + [9, 13], + [3, 14], + [9, 14], + [6, 15], + [4, 16], + [8, 16], + [5, 17], + [6, 17], + [7, 17], + [6, 18], + [3, 21], + [4, 21], + [5, 21], + [3, 22], + [4, 22], + [5, 22], + [2, 23], + [6, 23], + [1, 25], + [2, 25], + [6, 25], + [7, 25], + [3, 35], + [4, 35], + [3, 36], + [4, 36] + ], + "smallGlider": [ + [1, 1], + [2, 2], + [2, 3], + [1, 3], + [0, 3] + ], + "bigGlider": [ + [7, 19], + [7, 20], + [7, 21], + [8, 19], + [8, 22], + [8, 23], + [8, 24], + [9, 20], + [9, 22], + [10, 16], + [10, 17], + [10, 25], + [11, 16], + [11, 18], + [11, 23], + [11, 26], + [12, 16], + [12, 25], + [12, 26], + [13, 17], + [13, 18], + [14, 17], + [14, 20], + [14, 26], + [14, 28], + [14, 29], + [15, 17], + [15, 27], + [15, 28], + [15, 30], + [16, 19], + [16, 21], + [16, 28], + [16, 29], + [16, 32], + [17, 20], + [17, 21], + [17, 23], + [17, 28], + [17, 29], + [17, 33], + [18, 24], + [18, 32], + [19, 23], + [19, 24], + [19, 25], + [19, 26], + [19, 30], + [19, 32], + [20, 23], + [20, 25], + [20, 26], + [20, 30], + [20, 31], + [20, 32], + [20, 33], + [21, 24], + [21, 28], + [21, 29], + [21, 31], + [22, 29], + [22, 30], + [23, 25], + [23, 27], + [23, 28], + [23, 29], + [24, 26], + [24, 29] + ], + "Pulsar": [ + [7, 21], + [7, 22], + [7, 28], + [7, 29], + [8, 22], + [8, 23], + [8, 27], + [8, 28], + [9, 19], + [9, 22], + [9, 24], + [9, 26], + [9, 28], + [9, 31], + [10, 19], + [10, 20], + [10, 21], + [10, 23], + [10, 24], + [10, 26], + [10, 27], + [10, 29], + [10, 30], + [10, 31], + [11, 20], + [11, 22], + [11, 24], + [11, 26], + [11, 28], + [11, 30], + [12, 21], + [12, 22], + [12, 23], + [12, 27], + [12, 28], + [12, 29], + [14, 21], + [14, 22], + [14, 23], + [14, 27], + [14, 28], + [14, 29], + [15, 20], + [15, 22], + [15, 24], + [15, 26], + [15, 28], + [15, 30], + [16, 19], + [16, 20], + [16, 21], + [16, 23], + [16, 24], + [16, 26], + [16, 27], + [16, 29], + [16, 30], + [16, 31], + [17, 19], + [17, 22], + [17, 24], + [17, 26], + [17, 28], + [17, 31], + [18, 22], + [18, 23], + [18, 27], + [18, 28], + [19, 21], + [19, 22], + [19, 28], + [19, 29] + ], + "CircleOfFire": [ + [11, 24], + [11, 26], + [12, 22], + [12, 25], + [12, 28], + [13, 23], + [13, 25], + [13, 27], + [14, 21], + [14, 22], + [14, 23], + [14, 25], + [14, 27], + [14, 28], + [14, 29], + [15, 25], + [16, 20], + [16, 21], + [16, 22], + [16, 23], + [16, 24], + [16, 26], + [16, 27], + [16, 28], + [16, 29], + [16, 30], + [17, 25], + [18, 21], + [18, 22], + [18, 23], + [18, 25], + [18, 27], + [18, 28], + [18, 29], + [19, 23], + [19, 25], + [19, 27], + [20, 22], + [20, 25], + [20, 28], + [21, 24], + [21, 26] + ], + "Quadpole": [ + [11, 26], + [11, 27], + [12, 26], + [13, 27], + [13, 29], + [15, 29], + [15, 31], + [16, 32], + [17, 31], + [17, 32] + ], + "Spider": [ + [20, 23], + [20, 31], + [21, 17], + [21, 18], + [21, 20], + [21, 22], + [21, 24], + [21, 25], + [21, 29], + [21, 30], + [21, 32], + [21, 34], + [21, 36], + [21, 37], + [22, 14], + [22, 15], + [22, 16], + [22, 18], + [22, 20], + [22, 21], + [22, 22], + [22, 32], + [22, 33], + [22, 34], + [22, 36], + [22, 38], + [22, 39], + [22, 40], + [23, 14], + [23, 18], + [23, 20], + [23, 26], + [23, 28], + [23, 34], + [23, 36], + [23, 40], + [24, 18], + [24, 19], + [24, 26], + [24, 28], + [24, 35], + [24, 36], + [25, 15], + [25, 16], + [25, 26], + [25, 28], + [25, 38], + [25, 39], + [26, 15], + [26, 16], + [26, 18], + [26, 19], + [26, 35], + [26, 36], + [26, 38], + [26, 39], + [27, 19], + [27, 35] + ], + "B29": [ + [8, 26], + [8, 27], + [9, 25], + [9, 26], + [10, 27], + [11, 29], + [11, 30], + [12, 28], + [14, 27], + [14, 30], + [15, 24], + [15, 25], + [15, 27], + [16, 23], + [16, 24], + [16, 29], + [17, 25], + [17, 27], + [17, 30], + [18, 30], + [19, 27], + [19, 30], + [20, 28], + [20, 30], + [21, 28], + [21, 30], + [22, 29], + [22, 30], + [23, 29] + ] +} \ No newline at end of file diff --git a/Games/Life's_Mossaic/data/themes.json b/Games/Life's_Mossaic/data/themes.json new file mode 100644 index 0000000000..cbbc9276a1 --- /dev/null +++ b/Games/Life's_Mossaic/data/themes.json @@ -0,0 +1,98 @@ +{ + "blue": { + "--primary-color": "#0f045a", + "--theme-color1": "#7582b2", + "--theme-color2": "#036c96", + "--theme-color3": "#ebf2ff", + "--shadow-color1": "#352a7e", + "--shadow-color2": "#101536", + "--border-color1": "#080126", + "--background-col": "#c6cede", + "ALIVE_COLOR": "#00246B", + "DEAD_COLOR": "#CADCFC" + }, + "green": { + "--primary-color": "#045a1e", + "--theme-color1": "#75B289", + "--theme-color2": "#03962f", + "--theme-color3": "#EBFFEF", + "--shadow-color1": "#2A7E4D", + "--shadow-color2": "#10361C", + "--border-color1": "#01260B", + "--background-col": "#C6DECC", + "ALIVE_COLOR": "#006b2b", + "DEAD_COLOR": "#cafcdd" + }, + "red": { + "--primary-color": "#5a0404", + "--theme-color1": "#B27575", + "--theme-color2": "#960320", + "--theme-color3": "#FFEBEB", + "--shadow-color1": "#7E2A37", + "--shadow-color2": "#361015", + "--border-color1": "#260106", + "--background-col": "#DEC6C6", + "ALIVE_COLOR": "#6b0000", + "DEAD_COLOR": "#fccaca" + }, + "purple": { + "--primary-color": "#5a045a", + "--theme-color1": "#B275B2", + "--theme-color2": "#960396", + "--theme-color3": "#FFEBFF", + "--shadow-color1": "#7E2A7E", + "--shadow-color2": "#361036", + "--border-color1": "#260126", + "--background-col": "#DEC6DE", + "ALIVE_COLOR": "#6b006b", + "DEAD_COLOR": "#fcafcf" + }, + "darkCyan": { + "--primary-color": "#045a5a", + "--theme-color1": "#75B2B2", + "--theme-color2": "#039696", + "--theme-color3": "#EBFFFF", + "--shadow-color1": "#2A7E7E", + "--shadow-color2": "#103636", + "--border-color1": "#012626", + "--background-col": "#C6DEDE", + "ALIVE_COLOR": "#006b6b", + "DEAD_COLOR": "#cafcfc" + }, + "neon": { + "--primary-color": "#d0ff00", + "--theme-color1": "#00cc26", + "--theme-color2": "#00b81b", + "--theme-color3": "#004640", + "--shadow-color1": "#fc0101", + "--shadow-color2": "#000000", + "--border-color1": "#002628", + "--background-col": "#000525", + "ALIVE_COLOR": "#9800f5", + "DEAD_COLOR": "#80ffff" + }, + "black": { + "--primary-color": "#505050", + "--theme-color1": "#FFFFFF", + "--theme-color2": "#808080", + "--theme-color3": "#FFFFFF", + "--shadow-color1": "#808080", + "--shadow-color2": "#000000", + "--border-color1": "#000000", + "--background-col": "#FFFFFF", + "ALIVE_COLOR": "#000000", + "DEAD_COLOR": "#FFFFFF" + },"cyberpunk": { + "--primary-color": "#FCE4EC", + "--theme-color1": "#EC407A", + "--theme-color2": "#D81B60", + "--theme-color3": "#AD1457", + "--shadow-color1": "#FF0056", + "--shadow-color2": "#C2185B", + "--border-color1": "#880E4F", + "--background-col": "#FFF0F5", + "ALIVE_COLOR": "#EC407A", + "DEAD_COLOR": "#FCE4EC" +} + +} diff --git a/Games/Life's_Mossaic/desktop.ini b/Games/Life's_Mossaic/desktop.ini new file mode 100644 index 0000000000..814cb7d07f --- /dev/null +++ b/Games/Life's_Mossaic/desktop.ini @@ -0,0 +1,2 @@ +[LocalizedFileNames] +registerpage-favicon.png=@registerpage-favicon,0 diff --git a/Games/Life's_Mossaic/gamerules.css b/Games/Life's_Mossaic/gamerules.css new file mode 100644 index 0000000000..6053be2dd2 --- /dev/null +++ b/Games/Life's_Mossaic/gamerules.css @@ -0,0 +1,169 @@ +:root { + --primary-color: #0f045a; + --theme-color1: #7582b2; + --theme-color2: #036c96; + --theme-color3: #ebf2ff; + --shadow-color1: #352a7e; + --shadow-color2: #101536; + --border-color1: #080126; + --background-col: #c6cede; + --container-bg-color: #b0b8c4; + --scrollbar-color: #555555; +} + +.container { + max-width: 1200px; + width: 100%; + background-color: var(--container-bg-color); + color: var(--primary-color); + padding: 30px; + border-radius: 10px; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); +} + +* { + box-sizing: border-box; + margin: 0; + padding: 0; + font-family: "Roboto", sans-serif; +} + +body { + background-color: var(--background-col); + color: #333; + line-height: 1.6; + display: flex; + justify-content: center; + align-items: center; + min-height: 100vh; + padding: 20px; + position: relative; +} +h1 { + text-align: center; + font-size: 3rem; + color: var(--primary-color); + margin-bottom: 20px; + font-family: "Montserrat", sans-serif; +} + +h2, h3 { + color: var(--primary-color); + margin-top: 30px; + margin-bottom: 15px; + font-family: "Montserrat", sans-serif; +} + +h2 { + font-size: 2.5rem; + text-decoration: underline; +} + +h3 { + font-size: 2rem; + text-decoration: underline; +} + +p, ol { + font-size: 1.2rem; + color: #555; + margin-bottom: 1.5rem; + line-height: 1.8; +} + +ol { + padding-left: 20px; +} + +.center { + display: block; + margin: 20px auto; + max-width: 100%; + height: auto; + border-radius: 10px; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); +} + +table { + width: 100%; + margin: 30px auto; + border-collapse: collapse; + font-size: 1.2rem; + border-radius: 10px; + overflow: hidden; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); + background-color: #fff; +} + +table, th, td { + border: none; +} + +th, td { + padding: 15px; + text-align: center; +} + +th { + background-color: var(--primary-color); + color: #fff; + font-size: 1.4rem; + text-transform: uppercase; + letter-spacing: 0.1em; +} + +td { + background-color: var(--theme-color3); +} + +td img { + width: 30px; + height: auto; + transition: transform 0.3s, box-shadow 0.3s; +} + +td img:hover { + transform: scale(1.2); + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); +} + +.footer { + text-align: center; + font-size: 2rem; + color: var(--primary-color); + margin-top: 40px; + padding-top: 20px; + border-top: 2px solid var(--primary-color); +} + +hr { + border: 0; + height: 2px; + background: linear-gradient(to right, var(--primary-color), var(--theme-color3), var(--primary-color)); + margin: 30px 0; +} + .back-button { + position: fixed; + bottom: 90%; + left: 4%; + transform: translateX(-50%); + text-align: center; +} + +.home-icon { + width: 50px; + height: 50px; +} +.homeButton{ + text-align: center; +} +.back-to-home { + display: block; + margin: 20px auto; + padding: 10px 20px; + background-color: #4a3286; + color: white; + text-decoration: none; + border-radius: 5px; + font-size: 18px; +} diff --git a/Games/Life's_Mossaic/gamerules.html b/Games/Life's_Mossaic/gamerules.html new file mode 100644 index 0000000000..36a495e836 --- /dev/null +++ b/Games/Life's_Mossaic/gamerules.html @@ -0,0 +1,173 @@ + + + + + + + Game Rules + + + +
+ + Back to Home + +
+ +
+ +

How To Play?

+
+

Life's Mosaic

+

+ Life's Mosaic, or simply "Life," is a cellular automaton devised + by British mathematician John Horton Conway in 1970. It is a zero-player + game, meaning its evolution is determined by its initial state, + requiring no further input. Players interact with the game by creating + an initial configuration and observing how it evolves. The game is + Turing complete and can simulate a universal constructor or any other + Turing machine. +

+
+

The Universe

+

+ The universe of the Game of Life is an infinite, two-dimensional + orthogonal grid of square cells, Each cell is in one of two possible + states, ALIVE or DEAD. Every cell interacts with its eight neighbors, + which are the cells that are horizontally, vertically, or diagonally + adjacent. +

+
+

Rules

+
    +
  1. + Any live cell with fewer than two live neighbors dies, as if by + underpopulation. +
  2. +
  3. + Any live cell with two or three live neighbors lives on to the next + generation. +
  4. +
  5. + Any live cell with more than three live neighbors dies, as if by + overpopulation. +
  6. +
  7. + Any dead cell with exactly three live neighbors becomes a live cell, + as if by reproduction. +
  8. +
+

+ The first generation is created by applying the above rules + simultaneously to every cell in the seed, alive or dead; births and + deaths occur simultaneously, and the discrete moment at which this + happens is sometimes called a tick. Each generation is a pure function + of the preceding one. +

+

The Game

+ Game Grid + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Button Functions +
ButtonWhat they do
Pause ButtonStarts the animation after you've set the initial pattern
Play ButtonPauses the animation
+ Fast Forward Button + Increases the speed of the animation
+ Slow Down Button + Decreases the speed of the animation
Clear + Clears the grid on click, only if the game is not animating at that + moment +
RandomRandomly initializes the grid with initial randomness as 20%
+
+

The Presets

+
+

Glider

+

+ The glider is the smallest, most common, and first-discovered + spaceship in Game of Life. It travels diagonally across the grid. + Gliders are important because they are easily produced (by glider guns + and rakes), can be collided with each other to form more complicated + patterns, and can be used to transmit information over long distances. +

+ Small Glider +
+
+

Big Glider

+

+ The big glider was found by Dean Hickerson in December 1989 and was + the first known diagonal spaceship other than the glider. Two gliders + can be temporarily seen at the front of the ship; these do not stay + gliders but still move like them. +

+ Big Glider +
+
+

Gosper Glider Gun

+

+ The Gosper glider gun is the first known gun, and indeed the first + known finite pattern with unbounded growth, found by Bill Gosper in + November 1970. It consists of two queen bee shuttles stabilized by two + blocks. +

+ Gosper Glider Gun +
+
+

Summary

+

+ Life's Mosaic Life is a fascinating exploration of life, death, and + the rules that govern them. Despite its simplicity, it can lead to + complex and beautiful patterns.Life's Mosaic offers a unique way to + explore the unpredictable beauty of life itself. +

+ +
+ Back to Home +
+
+ + \ No newline at end of file diff --git a/Games/Life's_Mossaic/history.html b/Games/Life's_Mossaic/history.html new file mode 100644 index 0000000000..b17fe68386 --- /dev/null +++ b/Games/Life's_Mossaic/history.html @@ -0,0 +1,67 @@ + + + + + + + History of Life's Mosaic + + + +
+ + Back to Home + +
+ +
+ +

History of Life's Mosaic

+
+ +

Inception (1960s)

+

+ John Horton Conway, while at the University of Cambridge, was inspired by the work of John von Neumann, who sought to create a self-replicating machine. Conway aimed to find a simpler system that could emulate complex behavior and universality, leading to the creation of Life. +

+ +

Publication (1970)

+

+ Conway introduced the Game of Life in the October 1970 issue of "Scientific American," within Martin Gardner's "Mathematical Games" column. The simplicity of the game's rules and the complexity of its emergent behaviors quickly captivated mathematicians, computer scientists, and hobbyists. +

+ +

Initial Patterns

+

+ Early enthusiasts discovered a variety of fascinating patterns, including still lifes, oscillators, and spaceships. The "Glider" and the "Gosper Glider Gun" were among the first significant patterns identified, demonstrating movement and continuous growth within the system. +

+ +

Computational Significance

+

+ It was proven that the Game of Life is Turing complete, meaning it can simulate any Turing machine. This property underlines the game's potential to model complex systems and processes, despite its deceptively simple rules. +

+ +

Cultural Impact

+

+ The Game of Life gained widespread popularity in the 1970s and 1980s, particularly among early computer enthusiasts and within academic circles. It has been implemented in numerous programming languages and platforms, serving as a popular demonstration of cellular automata and emergent behavior. +

+ +

Modern Developments

+

+ The advent of more powerful computers has allowed for the exploration of larger and more complex patterns. Communities such as the "ConwayLife.com" forum continue to discover and share new patterns, contributing to the game's ongoing evolution. +

+ +
+

Summary

+

+ Conway's Game of Life, or Life's Mosaic, remains a profound example of how simple rules can give rise to rich and unexpected behaviors, influencing fields ranging from mathematics to computer science and artificial life research. +

+ + + +
+ Back to Home +
+ +
+ + + diff --git a/Games/Life's_Mossaic/images/Big-Glider.png b/Games/Life's_Mossaic/images/Big-Glider.png new file mode 100644 index 0000000000..bbc4d29f6d Binary files /dev/null and b/Games/Life's_Mossaic/images/Big-Glider.png differ diff --git a/Games/Life's_Mossaic/images/Fast-Forward-Button-Dark.svg b/Games/Life's_Mossaic/images/Fast-Forward-Button-Dark.svg new file mode 100644 index 0000000000..5debbf5510 --- /dev/null +++ b/Games/Life's_Mossaic/images/Fast-Forward-Button-Dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/Games/Life's_Mossaic/images/Fast-Forward-Button.svg b/Games/Life's_Mossaic/images/Fast-Forward-Button.svg new file mode 100644 index 0000000000..ce809ca803 --- /dev/null +++ b/Games/Life's_Mossaic/images/Fast-Forward-Button.svg @@ -0,0 +1,4 @@ + + + + diff --git a/Games/Life's_Mossaic/images/Fast-Reverse-Button-Dark.svg b/Games/Life's_Mossaic/images/Fast-Reverse-Button-Dark.svg new file mode 100644 index 0000000000..b08641f719 --- /dev/null +++ b/Games/Life's_Mossaic/images/Fast-Reverse-Button-Dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/Games/Life's_Mossaic/images/Fast-Reverse-Button.svg b/Games/Life's_Mossaic/images/Fast-Reverse-Button.svg new file mode 100644 index 0000000000..512d091e9f --- /dev/null +++ b/Games/Life's_Mossaic/images/Fast-Reverse-Button.svg @@ -0,0 +1,4 @@ + + + + diff --git a/Games/Life's_Mossaic/images/Game-Grid.png b/Games/Life's_Mossaic/images/Game-Grid.png new file mode 100644 index 0000000000..12f4e44a55 Binary files /dev/null and b/Games/Life's_Mossaic/images/Game-Grid.png differ diff --git a/Games/Life's_Mossaic/images/Gosper-Glider-Gun.png b/Games/Life's_Mossaic/images/Gosper-Glider-Gun.png new file mode 100644 index 0000000000..ac5d4d3d25 Binary files /dev/null and b/Games/Life's_Mossaic/images/Gosper-Glider-Gun.png differ diff --git a/Games/Life's_Mossaic/images/Pause-Button-Dark.svg b/Games/Life's_Mossaic/images/Pause-Button-Dark.svg new file mode 100644 index 0000000000..8e72453b8f --- /dev/null +++ b/Games/Life's_Mossaic/images/Pause-Button-Dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/Games/Life's_Mossaic/images/Pause-Button.svg b/Games/Life's_Mossaic/images/Pause-Button.svg new file mode 100644 index 0000000000..862d385177 --- /dev/null +++ b/Games/Life's_Mossaic/images/Pause-Button.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/Games/Life's_Mossaic/images/Play-Button-Dark.svg b/Games/Life's_Mossaic/images/Play-Button-Dark.svg new file mode 100644 index 0000000000..c8ad86ef52 --- /dev/null +++ b/Games/Life's_Mossaic/images/Play-Button-Dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/Games/Life's_Mossaic/images/Play-Button.svg b/Games/Life's_Mossaic/images/Play-Button.svg new file mode 100644 index 0000000000..7d39144068 --- /dev/null +++ b/Games/Life's_Mossaic/images/Play-Button.svg @@ -0,0 +1,4 @@ + + + + diff --git a/Games/Life's_Mossaic/images/Small-Glider.png b/Games/Life's_Mossaic/images/Small-Glider.png new file mode 100644 index 0000000000..32ddd31a11 Binary files /dev/null and b/Games/Life's_Mossaic/images/Small-Glider.png differ diff --git a/Games/Life's_Mossaic/images/desktop.ini b/Games/Life's_Mossaic/images/desktop.ini new file mode 100644 index 0000000000..814cb7d07f --- /dev/null +++ b/Games/Life's_Mossaic/images/desktop.ini @@ -0,0 +1,2 @@ +[LocalizedFileNames] +registerpage-favicon.png=@registerpage-favicon,0 diff --git a/Games/Life's_Mossaic/images/glider-icon.png b/Games/Life's_Mossaic/images/glider-icon.png new file mode 100644 index 0000000000..945b359dd9 Binary files /dev/null and b/Games/Life's_Mossaic/images/glider-icon.png differ diff --git a/Games/Life's_Mossaic/images/home.png b/Games/Life's_Mossaic/images/home.png new file mode 100644 index 0000000000..e4bb3f9a78 Binary files /dev/null and b/Games/Life's_Mossaic/images/home.png differ diff --git a/Games/Life's_Mossaic/images/registerpage-favicon.png b/Games/Life's_Mossaic/images/registerpage-favicon.png new file mode 100644 index 0000000000..945b359dd9 Binary files /dev/null and b/Games/Life's_Mossaic/images/registerpage-favicon.png differ diff --git a/Games/Life's_Mossaic/index.html b/Games/Life's_Mossaic/index.html new file mode 100644 index 0000000000..e6bd544a64 --- /dev/null +++ b/Games/Life's_Mossaic/index.html @@ -0,0 +1,275 @@ + + + + + + + + + + Life's Mosaic + + + + + + + + + + + + + + + + + + + + + +
+ +
+
Settings
+
+ +
+ +
+
+ + +
+
+ + +
+

+ + +

+
+
Themes
+
+
    +
  • +
    + + +
    +
  • +
+
    +
  • +
    + + +
    +
  • +
+
    +
  • +
    + + +
    +
  • +
+
    +
  • +
    + + +
    +
  • +
+
    +
  • +
    + + +
    +
  • +
+
    +
  • +
    + + +
    +
  • +
+
    +
  • +
    + + +
    +
  • +
  • +
    + + +
    +
  • +
+
+ + +
+
+
Presets
+
+
    +
  • + +
  • +
+
    +
  • + +
  • +
+
    +
  • + +
  • +
+
    +
  • + +
  • +
+
    +
  • + +
  • +
+
    +
  • + +
  • +
+
    +
  • + +
  • +
+
+
History
+
+
+ + +
+ +
+
+
+ + + + + +
+
Life's Mosaic
+
+
+
+
+
+ + Clear the grid +
+
+ + Rewind +
+
+ + Start or Pause the animation +
+
+ + Fast Forward +
+
+ + Random +
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/Games/Life's_Mossaic/js/app.js b/Games/Life's_Mossaic/js/app.js new file mode 100644 index 0000000000..67b70e4649 --- /dev/null +++ b/Games/Life's_Mossaic/js/app.js @@ -0,0 +1,588 @@ +// const { get } = require("animejs"); +const WIDTH = 60; +const HEIGHT = 30; + +let ALIVE_COLOR = "#00246B"; +let DEAD_COLOR = "#CADCFC"; + +const ALIVE = 1; +const DEAD = 0; + + +// 2D array to hold cell states +let cells = new Array(HEIGHT); +for (let i = 0; i < HEIGHT; i++) { + cells[i] = new Array(WIDTH); +} + +let animationSpeed = 400; +let randomValue = 20; +let isAnimating = false; +let isStarted = false; +let areEventListenersAdded = true; +let isWarpEnabled = true; +let isGridVisible = true; +let aliveCount = 0; + + + +function onResizeAboveThreshold() { + const thresholdWidth = 750; + const currentWidth = window.innerWidth; + + if (currentWidth >= thresholdWidth) { + document.querySelector(".sidenav").style.left = "0px" + }else{ + document.querySelector(".sidenav").style.left = "0px" + } +} +onResizeAboveThreshold(); +window.addEventListener('resize', onResizeAboveThreshold); + + +document.querySelector(".hamburger").addEventListener("click", () => { + document.querySelector(".sidenav").style.left = "0px" +}) + + + +document.querySelector(".cross").addEventListener("click", () => { + document.querySelector(".sidenav").style.left = "0px" +}) + +var slider = document.getElementById("randomVal"); +var output = document.getElementById("randomValOutput"); +output.innerHTML = slider.value; + +slider.oninput = function () { + output.innerHTML = this.value; + randomValue = this.value; +}; + +document.addEventListener("DOMContentLoaded", function () { + // Generate the grid + for (let i = 0; i < HEIGHT; i++) { + // Push an empty array for each row + for (let j = 0; j < WIDTH; j++) { + cells[i][j] = DEAD; // Initialize cell state + // Create a new cell element + const cell = document.createElement("div"); + cell.classList.add("cell"); + // Append the cell to the grid container + gridContainer.appendChild(cell); + } + } + + gridContainer.style.gridTemplateRows = `repeat(${HEIGHT}, calc((100%) / ${HEIGHT}))`; + gridContainer.style.gridTemplateColumns = `repeat(${WIDTH}, calc((100%) / ${WIDTH}))`; + // set grid container size according to ratio + gridContainer.style.minHeight = "30vw"; + gridContainer.style.minWidth = "60vw"; + handleDropdowns(); + addEventListenersToCells(); + drawCells(); +}); + +// draw the cells according to the state +// using style of "cell" class to change the color of the cell, iterate over it +function drawCells() { + const cellElements = gridContainer.querySelectorAll(".cell"); + cells.forEach((row, i) => { + row.forEach((cell, j) => { + const cellDiv = cellElements[i * WIDTH + j]; + const newColor = cell === ALIVE ? ALIVE_COLOR : DEAD_COLOR; + // Only update if colour changes + if (cellDiv.style.backgroundColor !== newColor) { + cellDiv.style.backgroundColor = newColor; + } + }); + }); +} + +// Map to store event listener functions for each cell +const cellEventListeners = new Map(); + +function addEventListenersToCells() { + const cellElements = document.querySelectorAll(".cell"); + cellElements.forEach(function (cell, index) { + const listener = function () { + handleClick(index); + }; + cellEventListeners.set(cell, listener); + cell.addEventListener("click", listener); + }); +} + +function removeEventListenersFromCells() { + const cellElements = document.querySelectorAll(".cell"); + cellElements.forEach(function (cell) { + const listener = cellEventListeners.get(cell); + if (listener) { + cell.removeEventListener("click", listener); + cellEventListeners.delete(cell); + } + }); +} + +function handleClick(i) { + const row = Math.floor(i / WIDTH); + const col = i % WIDTH; + // Toggle cell state + cells[row][col] = cells[row][col] === ALIVE ? DEAD : ALIVE; + + if(cells[row][col] == ALIVE) aliveCount++; + else aliveCount--; + + // Redraw cells + drawCells(); +} + +async function getPresets() { + try { + const response = await fetch("../data/presets.json"); + const data = await response.json(); + return data; + } catch (error) { + return null; + } +} + +async function drawPresetPattern(presetName) { + try { + const presetsList = await getPresets(); + if (!presetsList) { + return; + } + const preset = presetsList[presetName]; + if (preset) { + if (!isStarted && !isAnimating) { + // Clear the grid + clearGrid(); + preset.forEach((coord) => { + let [x, y] = coord; + // Ensure coordinates are within the bounds of the cells array + if (x >= 0 && x < HEIGHT && y >= 0 && y < WIDTH) { + cells[x][y] = ALIVE; + aliveCount++; + } + }); + // Call drawCells to update the grid + drawCells(); + } + } + drawCells(); + } catch (error) { + console.error("Error:", error); + } +} + +async function getThemes() { + try { + const response = await fetch("../data/themes.json"); + const data = await response.json(); + return data; + } catch (error) { + return null; + } +} + +// async function selectTheme(themeName) { +// try { +// const themesList = await getThemes(); +// if (!themesList) { +// return; +// } + +// const theme = themesList[themeName]; +// if (theme) { +// const root = document.documentElement; +// for (const key in theme) { +// root.style.setProperty(key, theme[key]); +// } +// ALIVE_COLOR = theme["ALIVE_COLOR"]; +// DEAD_COLOR = theme["DEAD_COLOR"]; +// } else { +// console.error("Theme not found"); +// } +// drawCells(); +// } catch (error) { +// console.error("Error:", error); +// } +// } + +async function selectTheme(themeName) { + try { + const themesList = await getThemes(); + if (!themesList) { + return; + } + + const theme = themesList[themeName]; + if (theme) { + const root = document.documentElement; + const backgroundContainer = document.body; // Change this to the appropriate container if needed + + for (const key in theme) { + root.style.setProperty(key, theme[key]); + } + + // Check if the theme contains a gradient + if (theme["background-image"]) { + backgroundContainer.style.backgroundImage = theme["background-image"]; + backgroundContainer.style.backgroundColor = ''; // Reset background color + } else { + backgroundContainer.style.backgroundImage = 'none'; // Remove gradient + backgroundContainer.style.backgroundColor = theme["background-color"]; // Apply solid color + var container = document.querySelector('.game'); + container.style.background = ''; + } + + root.style.setProperty('--scrollbar-color', theme['--primary-color']); + ALIVE_COLOR = theme["ALIVE_COLOR"]; + DEAD_COLOR = theme["DEAD_COLOR"]; + let reverse_button = document.getElementById('fast-reverse-button'); + let forward = document.getElementById('fast-forward-button'); + let pause_button = document.getElementById('play-pause-button'); + + if (theme["DEAD_COLOR"] == "#80ffff") { + reverse_button.innerHTML = "Play"; + forward.innerHTML = "Fast"; + pause_button.innerHTML = "Slow"; + } else { + reverse_button.innerHTML = "Play"; + forward.innerHTML = "Fast"; + pause_button.innerHTML = "Slow"; + } + + // If switching from a gradient theme to a solid color theme, reset the background + if (!theme["background-image"]) { + backgroundContainer.style.backgroundImage = 'none'; + } + } else { + console.error("Theme not found"); + } + drawCells(); + } catch (error) { + console.error("Error:", error); + } +} + + + +function increaseSpeed() { + // increase the speed of the animation + if (animationSpeed > 1) { + animationSpeed /= 1.1; + } +} + +function decreaseSpeed() { + // decrease the speed of the animation + animationSpeed *= 1.1; +} + +function isEmpty() { + return (aliveCount==0); +} + +function startAnimation() { + // check if the grid is empty, + // if not then start the animation and start the game + if (areEventListenersAdded) { + removeEventListenersFromCells(); + areEventListenersAdded = false; + } + const playPauseIcon = document.getElementById("play-pause-icon"); + if (isEmpty()) { + playPauseIcon.src = DEAD_COLOR=="#80ffff"?"./images/Play-Button-Dark.svg": "./images/Play-Button.svg"; + if (!areEventListenersAdded) { + addEventListenersToCells(); + areEventListenersAdded = true; + } + isAnimating = false; + isStarted = false; + } else { + // if game is not started, set it to true + // if pause is clicked, pause the game + isAnimating = !isAnimating; + // check if the game is started + // if not, set it to true + if (isStarted == false) { + isStarted = true; + // storePattern(cells); + storePattern(cells, aliveCount); + appendPatternButtons(); + } + // change the icon according to the state + if(DEAD_COLOR=="#80ffff"){ + console.log('ggggg') + playPauseIcon.src=isAnimating + ? "./images/Pause-Button-Dark.svg" + : "./images/Play-Button-Dark.svg"; + }else{ + playPauseIcon.src = isAnimating + ? "./images/Pause-Button.svg" + : "./images/Play-Button.svg"; + } + } + if (isAnimating) { + animate(); + } +} + +//randomGrid() +function randomGrid() { + // if the game is not started and not animating + // then allow user to set the cells to random state + aliveCount = 0; + if (!isStarted && !isAnimating) { + for (let i = 0; i < HEIGHT; i++) { + for (let j = 0; j < WIDTH; j++) { + cells[i][j] = Math.random() * 100 < randomValue ? ALIVE : DEAD; + if(cells[i][j] == ALIVE) aliveCount++; + } + } + drawCells(); + } +} + +function clearGrid() { + // if the game is paused + // then allow user to clear the grid + if (!isAnimating) { + aliveCount = 0; + for (let i = 0; i < HEIGHT; i++) { + for (let j = 0; j < WIDTH; j++) { + cells[i][j] = DEAD; + } + } + drawCells(); + } + isStarted = false; + if (!areEventListenersAdded) { + addEventListenersToCells(); + areEventListenersAdded = true; + } +} + +function toggleWarp() { + isWarpEnabled = !isWarpEnabled; +} + +function toggleGrid() { + isGridVisible = !isGridVisible; + var root = document.documentElement; + // Get the computed styles of the root element + var style = getComputedStyle(root); + // get border-color1 from the root + let borderColor = style.getPropertyValue("--border-color1"); + let borderVal = isGridVisible ? `solid 0.001rem ${borderColor}` : "none"; + const cellElements = gridContainer.querySelectorAll(".cell"); + cellElements.forEach((cell) => { + cell.style.border = borderVal; + }); +} + +function countNeighbors(cells, x, y, wrapEdges) { + const positions = [ + [-1,-1], [-1, 0], [-1, 1], + [ 0,-1], [ 0, 1], + [ 1,-1], [ 1, 0], [ 1, 1] + ]; + + return positions.reduce((acc, [dx, dy]) => { + const nx = wrapEdges ? (x + dx + HEIGHT) % HEIGHT : x + dx; + const ny = wrapEdges ? (y + dy + WIDTH) % WIDTH : y + dy; + if (nx >= 0 && nx < HEIGHT && ny >= 0 && ny < WIDTH && cells[nx][ny] === ALIVE) { + acc++; + } + return acc; + }, 0); +} + +function calculateNextGeneration(cells, wrapEdges) { + const nextGeneration = Array.from({ length: HEIGHT }, () => Array(WIDTH).fill(DEAD)); + let aliveCountTemp = 0; + + for (let i = 0; i < HEIGHT; i++) { + for (let j = 0; j < WIDTH; j++) { + const numNeighbors = countNeighbors(cells, i, j, wrapEdges); + + //Rule 1: Any live cell with fewer than two live neighbors dies, as if by underpopulation. + //Rule 2: Any live cell with two or three live neighbors lives on to the next generation. + //Rule 3: Any live cell with more than three live neighbors dies, as if by overpopulation. + //Rule 4: Any dead cell with exactly three live neighbors becomes a live cell, as if by reproduction. + const isAlive = (cells[i][j] === ALIVE); + if ((isAlive && (numNeighbors === 2 || numNeighbors === 3)) || (!isAlive && numNeighbors === 3)) { + nextGeneration[i][j] = ALIVE; + aliveCountTemp++; + } + } + } + aliveCount = aliveCountTemp; + return nextGeneration; +} + +function animate() { + // Update cells with the new generation + cells = calculateNextGeneration(cells, isWarpEnabled); + setTimeout(() => { + drawCells(); // Draw cells after a delay + if (isAnimating) { + requestAnimationFrame(animate); // Keep animating + } + }, animationSpeed); +} + +//* Loop through all dropdown buttons to toggle between hiding and showing its dropdown content - This allows the user to have multiple dropdowns without any conflict */ +function handleDropdowns() { + var themesDropdown = document.getElementsByClassName("color-themes"); + var presetsDropdown = document.getElementsByClassName("presets"); + var historyDropdown = document.getElementsByClassName("history"); + for (let i = 0; i < themesDropdown.length; i++) { + themesDropdown[i].addEventListener("click", function () { + this.classList.toggle("active"); + let dropdownContent = this.nextElementSibling; + if (dropdownContent.style.display === "block") { + dropdownContent.style.display = "none"; + } else { + dropdownContent.style.display = "block"; + } + }); + } + for (let i = 0; i < presetsDropdown.length; i++) { + presetsDropdown[i].addEventListener("click", function () { + this.classList.toggle("active"); + let dropdownContent = this.nextElementSibling; + if (dropdownContent.style.display === "block") { + dropdownContent.style.display = "none"; + } else { + dropdownContent.style.display = "block"; + } + }); + } + for (let i = 0; i < historyDropdown.length; i++) { + historyDropdown[i].addEventListener("click", function () { + this.classList.toggle("active"); + let dropdownContent = this.nextElementSibling; + if (dropdownContent.style.display === "block") { + dropdownContent.style.display = "none"; + } else { + dropdownContent.style.display = "block"; + } + }); + } +} + +let historyCount = 0; + +function storePattern(pattern) { + // Convert the 2D array to a JSON string + const patternJson = JSON.stringify(pattern); + + // Retrieve the current history from session storage + let history = sessionStorage.getItem("patternHistory"); + if (history) { + history = JSON.parse(history); + } else { + history = []; + } + + // Add the new pattern to the history + history.unshift(patternJson); // Add to the beginning + + // Check if the history exceeds 5 patterns + if (history.length > 5) { + // Remove the oldest pattern + history.pop(); + } + historyCount = history.length; + + // Store the updated history back in session storage + sessionStorage.setItem("patternHistory", JSON.stringify(history)); +} + +function getPatternHistory() { + // Retrieve the pattern history from session storage + const historyJson = sessionStorage.getItem("patternHistory"); + if (historyJson) { + // Parse the JSON string back into an array + const history = JSON.parse(historyJson); + // Convert each pattern JSON string back into a 2D array + return history.map((patternJson) => JSON.parse(patternJson)); + } + return []; +} + +function appendPatternButtons() { + const historyContainer = document.querySelector(".history-container"); + const patterns = getPatternHistory(); // Retrieve the pattern history + + // Clear the container first + historyContainer.innerHTML = ""; + + // Loop through the patterns and create a button for each + patterns.forEach((pattern, index) => { + const button = document.createElement("button"); + button.textContent = `${index + 1}`; // Button names start from the most recent + button.addEventListener("click", () => { + // When a button is clicked, set the cells array to the corresponding pattern + if (!isAnimating && !isStarted) { + cells = pattern; + aliveCount = (cells.flat().filter(cell => cell === ALIVE).length); + } + drawCells(); // Assuming drawCells is a function you have that draws the cells on the screen + }); + historyContainer.appendChild(button); + }); +} + +document.querySelectorAll('[data-tooltip]').forEach(elem => { + let tooltipTimeout; + + elem.addEventListener('mouseenter', function() { + tooltipTimeout = setTimeout(() => { + const tooltip = document.createElement('div'); + tooltip.className = 'tooltip'; + tooltip.innerText = elem.getAttribute('data-tooltip'); + document.body.appendChild(tooltip); + + const rect = elem.getBoundingClientRect(); + tooltip.style.left = rect.left + (rect.width / 2) - (tooltip.offsetWidth / 2) + 'px'; + tooltip.style.top = rect.top - tooltip.offsetHeight - 10 + 'px'; + + elem._tooltip = tooltip; + }, 500); // Delay of 500ms + }); + + elem.addEventListener('mouseleave', function() { + clearTimeout(tooltipTimeout); + if (elem._tooltip) { + elem._tooltip.remove(); + elem._tooltip = null; + } + }); +}); + +// Function to show tooltip +function showTooltip(event) { + const tooltip = event.currentTarget.querySelector('.tooltip-text'); + tooltip.style.visibility = 'visible'; + tooltip.style.opacity = '1'; +} + +// Function to hide tooltip +function hideTooltip(event) { + const tooltip = event.currentTarget.querySelector('.tooltip-text'); + tooltip.style.visibility = 'hidden'; + tooltip.style.opacity = '0'; +} + +// Attach event listeners to all buttons with tooltips +document.querySelectorAll('.tooltip-container').forEach(container => { + container.addEventListener('mouseenter', showTooltip); + container.addEventListener('mouseleave', hideTooltip); +}); + + +const gridContainer = document.getElementById("main-grid"); diff --git a/Games/Life's_Mossaic/js/gradient.js b/Games/Life's_Mossaic/js/gradient.js new file mode 100644 index 0000000000..fff27e9405 --- /dev/null +++ b/Games/Life's_Mossaic/js/gradient.js @@ -0,0 +1,32 @@ +// Function to apply gradient theme +function applyGradientTheme(color1, color2, direction) { + var container = document.querySelector('.game'); + container.style.background = 'linear-gradient(' + direction + ', ' + color1 + ', ' + color2 + ')'; + var title = document.querySelector('.heading'); + title.style.color = isDark(color1) ? '#ffffff' : '#000000'; +} + +// Event listener for the gradient theme button +document.getElementById('gradient-theme-btn').addEventListener('click', function() { + var colorsContainer = document.getElementById('gradient-colors-container'); + colorsContainer.style.display = (colorsContainer.style.display === 'block') ? 'none' : 'block'; +}); + +// Event listener for the Apply Gradient button +document.getElementById('apply-gradient-btn').addEventListener('click', function() { + var color1 = document.getElementById('color1').value; + var color2 = document.getElementById('color2').value; + var direction = document.getElementById('gradient-direction').value; // Get the selected gradient direction + applyGradientTheme(color1, color2, direction); + document.getElementById('gradient-colors-container').style.display = 'none'; +}); + +// Function to check the brightness of a color +function isDark(color) { + const rgb = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(color); + const r = parseInt(rgb[1], 16); + const g = parseInt(rgb[2], 16); + const b = parseInt(rgb[3], 16); + const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255; + return luminance < 0.5; +} \ No newline at end of file diff --git a/Games/Life's_Mossaic/package-lock.json b/Games/Life's_Mossaic/package-lock.json new file mode 100644 index 0000000000..abff63d360 --- /dev/null +++ b/Games/Life's_Mossaic/package-lock.json @@ -0,0 +1,21 @@ +{ + "name": "gameoflife", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "gameoflife", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "animejs": "^3.2.2" + } + }, + "node_modules/animejs": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/animejs/-/animejs-3.2.2.tgz", + "integrity": "sha512-Ao95qWLpDPXXM+WrmwcKbl6uNlC5tjnowlaRYtuVDHHoygjtIPfDUoK9NthrlZsQSKjZXlmji2TrBUAVbiH0LQ==" + } + } +} diff --git a/Games/Life's_Mossaic/package.json b/Games/Life's_Mossaic/package.json new file mode 100644 index 0000000000..d41c704934 --- /dev/null +++ b/Games/Life's_Mossaic/package.json @@ -0,0 +1,14 @@ +{ + "name": "gameoflife", + "version": "1.0.0", + "description": "", + "main": "app.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "dependencies": { + "animejs": "^3.2.2" + } +} diff --git a/Games/Life's_Mossaic/style.css b/Games/Life's_Mossaic/style.css new file mode 100644 index 0000000000..7dca49ad20 --- /dev/null +++ b/Games/Life's_Mossaic/style.css @@ -0,0 +1,603 @@ +* { + box-sizing: border-box; + margin: 0; + padding: 0; + user-select:none; +} + +body { + -webkit-user-select: none; /* Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* Internet Explorer/Edge */ + user-select: none; /* Standard syntax */ +} + +:root { + --primary-color: #251f4d; + --theme-color1: #7582b2; + --theme-color2: #036c96; + --theme-color3: #ebf2ff; + --shadow-color1: #352a7e; + --shadow-color2: #101536; + --border-color1: #080126; + --background-col: #c6cede; + --scrollbar-color: #555555; +} + +body { + font-family: 'Roboto Mono', monospace; + background: linear-gradient(135deg, #ebf2ff 0%, #7582b2 100%); + color: #333; + transition: background 0.5s ease; +} + +::-webkit-scrollbar { + width: 8px; +} + +::-webkit-scrollbar-track { + background: var(--shadow-color2); +} + +::-webkit-scrollbar-thumb { + background: var(--scrollbar-color); +} +body{ + background-color: var(--background-col); +}/* button */ +.button-73 { + appearance: none; + background-color: #FFFFFF; + border-radius: 40em; + border-style: none; + box-shadow: #ADCFFF 0 -12px 6px inset; + box-sizing: border-box; + color: #000000; + cursor: pointer; + display: inline-block; + font-family: -apple-system,sans-serif; + font-size: 1.2rem; + font-weight: 700; + letter-spacing: -.24px; + margin: 0; + outline: none; + padding: 1rem 1.3rem; + quotes: auto; + text-align: center; + text-decoration: none; + transition: all .15s; + user-select: none; + -webkit-user-select: none; + touch-action: manipulation; +} + +.button-73:hover { + background-color: #FFC229; + box-shadow: #FF6314 0 -6px 8px inset; + transform: scale(1.125); +} + +.button-73:active { + transform: scale(1.025); +} +.heading { + text-align: center; + padding-top: 1.5rem; + padding-bottom: 1.5rem; + margin-top: 0.5rem; + font-size: 3rem; + font-weight: bold; + color: var(--primary-color); + text-shadow: 2px 2px 4px var(--shadow-color1); + transition: color 0.3s ease, text-shadow 0.3s ease; +} + +.great-vibes-regular { + font-family: "Great Vibes", cursive; + /* font-weight: 400; */ + letter-spacing: 1px; + font-style: normal; +} + +.game { + position: relative; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + height: 100vh; + max-width: 100vw; + margin-left: 20vw; + background-color: var(--background-col); + transition: background-color 0.5s ease; +} +.full-width{ + margin-left: 0; +} +.grid-container { + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + border: solid 0.2rem var(--border-color1); + max-width: 62vw; + max-height: 31vw; + transition: border-color 0.3s ease; +} + +.main-grid { + display: grid; + justify-content: center; + margin: auto; + background-color: inherit; +} + +.cell { + display: flex; + justify-content: center; + align-items: center; + border: solid 0.001rem var(--border-color1); + cursor: pointer; + transition:0.2s ease; +} +.cell:hover{ + transform: scale(1.3); + border:1px solid white ; +} +.cell:active{ + scale: 1; +} +.controls { + display: flex; + flex-direction: row; /* Ensure buttons are in a row */ + justify-content: center; + align-items: center; + margin-top: 1rem; + margin-bottom: 1rem; + transition: all 0.3s ease; +} + +.control-button { + border: none; + background: none; + padding: 1rem; + cursor: pointer; + outline: none; + transition: transform 0.2s ease; +} + +.control-button:hover { + transform: scale(1.1); +} + +.icon { + width: calc((30vw) / 8); + height: calc((30vw) / 8); +} + +.clear-button, +.random-button { + border: solid 0.1rem var(--border-color1); + border-radius: 0.6rem; + height: calc((100%) / 1.8); + width: auto; + text-align: center; + padding: 0.5rem; + font-family: 'Roboto Mono', monospace; + font-weight: bold; + font-size: 1.1rem; + color: var(--primary-color); + background-color: var(--theme-color3); + transition: box-shadow 0.3s ease, transform 0.2s ease; + margin: 0 0.5rem; /* Add margin to separate buttons */ +} +.clear-button { + margin-right: 1rem; +} + +.random-button { + margin-left: 1rem; +} + +.clear-button:hover, +.random-button:hover { + box-shadow: 0.1rem 0.1rem var(--shadow-color1); +} + +.clear-button:active, +.random-button:active { + box-shadow: 0.1rem 0.1rem var(--shadow-color2); + transform: translateY(0.1rem); +} + +.icon:active { + transform: translateY(0.1rem); +} +#toggleButton { + color: black; + border-radius: 5px; + border-style: none; + font-size: 1.7rem; + background: none; + margin: 1px; + z-index: 1; + position: absolute; + left: 2rem; + top: 1.8rem; +} +.sidenav { + height: 100vh; + width: 20vw; + position: fixed; + top: 0; + left: 0; + z-index: 2; + background-color: var(--border-color1); + overflow-x:hidden; + padding-top: 2rem; + transition: left 0.3s ease, width 0.3s ease; +} +/* Hide the nav bar */ +.hide-nav { + display: none; +} + +.sidenav .cross { + cursor: pointer; + position: absolute; + top: 45px; + right: 15px; + display: block; +} + +.sidenav button, +.other-settings, +.other-settings-container div, +.presets-container div, +.color-themes, +.themes-container div, +.presets, +.history, +.game-rules, +.game-rules-container{ + padding: 0.8rem 0.5rem 0.8rem 1.6rem; + text-decoration: none; + font-size: 1rem; + color: #818181; + font-family: 'Roboto Mono', monospace; + font-weight: lighter; + display: block; + border: none; + background: none; + width: 100%; + text-align: left; + /* cursor: pointer; */ + outline: none; + transition: color 0.3s ease; +} + +.other-settings-container .randomness-container { + padding: 0.8rem 0.5rem 0.8rem 1.6rem; + text-decoration: none; + font-size: 1rem; + color: #818181; + font-family: 'Roboto Mono', monospace; + font-weight: lighter; + display: block; + border: none; + background: none; + width: 100%; + text-align: left; + cursor: pointer; + outline: none; +} + +.hamburger { + position: absolute; + left: 10px; + top: 5px; + display: none; +} + +.has-dropdown:hover { + color: #fff; +} + +.active { + background-color: var(--theme-color2); + color: white; +} + +.other-settings, +.color-themes, +.presets, +.history +.game-rules{ + font-size: 1.2rem; +} + +.other-settings { + font-weight: bold; + color: var(--theme-color1); +} + +.other-settings-container { + background-color: var(--shadow-color2); +} + +.themes-container, +.presets-container, +.history-container, +.game-rules-container{ + display: none; + background-color: var(--shadow-color2); + padding-left: 0.2rem; +} + +.presets-list:active, +.history-container, +.color-label:hover{ + cursor: pointer; +} + +.randomness-value { + max-width: 80%; + padding-bottom: 0.6rem; + display: flex; + align-items: center; + justify-content: space-between; +} + +.slider { + width: 80%; + border-radius: 0.2rem; + background: var(--theme-color3); + outline: none; + opacity: 0.7; + -webkit-transition: opacity 0.2s; + transition: opacity 0.2s; +} + +.slider:hover { + opacity: 1; +} + +@media screen and (max-width: 768px) { + .controls { + flex-direction: column; /* Stack buttons vertically on smaller screens */ + align-items: center; /* Center buttons vertically */ + min-width: 25vw; + margin: none; + } + + .sidenav { + height: auto; + position: fixed; + padding-top: 0.5rem; + left: -250px; + height: 100vh; + transition: width 0.3s ease; + width: 20rem; + padding-top: 2rem; + } + + .hamburger { + position: absolute; + left: 10px; + top: 5px; + display: none; + } + + .sidenav .cross { + cursor: pointer; + position: absolute; + top: 13px; + right: 10px; + display: block; + padding-top: 1.6rem; + } + + .sidenav .randomness-container input { + text-decoration: none; + font-size: 0.8rem; + display: block; + border: none; + background: none; + width: 50%; + text-align: center; + cursor: pointer; + outline: none; + align-items: center; + } + + .sidenav .randomness-container label { + padding: 0.6rem 4.4rem 0.6rem 0; + text-decoration: none; + font-size: 1rem; + display: block; + border: none; + background: none; + width: 50%; + cursor: pointer; + outline: none; + } + .sidenav button, + .other-settings-container div, + .presets-container div, + .color-themes, + .themes-container div, + .presets, + .history, + + .other-settings{ + padding: 3px; + text-align: center; + } + + .game { + width: 100vw; + margin: 0; + } + .controls { + display: flex; + flex-direction: row; + min-width: 25vw; + height: auto; + justify-content: center; + align-items: center; + margin-top: 1rem; + margin-bottom: 1rem; + transition: all 0.3s ease; + } + + .clear-button, + .random-button { + font-size: 0.8rem; + /* Adjust font size for smaller screens */ + padding: 0.3rem 0.8rem; + /* Adjust padding for smaller screens */ + margin: 0.5rem 0; + /* Add margin to separate buttons vertically */ + } + + .grid-container { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + border: solid 0.2rem var(--border-color1); + max-width: 80vw; + max-height: 82vw; + transition: border-color 0.3s ease; + } + + .icon { + width: calc((30vw) / 8); + height: calc((30vw) / 8); + } + + .heading { + font-size: 1.7rem; + text-align: center; + padding-top: 0.7rem; + padding-bottom: 0.7rem; + } +} + +/* ----------- Contact us section ---------------------------*/ +.socialIcons { + display: none; + justify-content: center; + background: transparent; + border: 2px; + border-color: #a254e6; + margin-top: 15px; + margin-bottom: 15px; +} + +.socialIcons a { + text-decoration: none; + padding: 10px; + background-color: #fff; + margin: 10px; /* Reduced margin */ + border-radius: 50%; +} +.socialIcons a img { + width: 20px; /* Adjusted icon size */ + height: 20px; +} + +.socialIcons a:hover { + background-color: #4f66c1; + transition: 0.5s; +} + +.socialIcons a:hover img { + filter: invert(1); /* Invert icon color on hover */ + transition: 0.5s; + +} + +/* Hover Effects */ +.warp-on-edges:hover, +.grid-toggle:hover, +.randomness-container:hover{ + color:white; +} +/*-----------------------------------------*/ + + +/* Tooltip container */ +.tooltip-container { + position: relative; + display: inline-block; +} + +/* Tooltip text */ +.tooltip-text { + visibility: hidden; + width: 120px; + background-color: var(--theme-color2); + color: #fff; + text-align: center; + padding: 5px 0; + border-radius: 6px; + position: absolute; + z-index: 1; + bottom: 125%; /* Position the tooltip above the button */ + left: 50%; + margin-left: -60px; + opacity: 0; + transition: opacity 0.3s; +} + +.tooltip-container:hover .tooltip-text, +.tooltip-container:focus .tooltip-text { + visibility: visible; + opacity: 1; +} + +.tooltip-text::after { + content: ""; + position: absolute; + top: 100%; + left: 50%; + margin-left: -5px; + border-width: 5px; + border-style: solid; + border-color: var(--theme-color2) transparent transparent transparent; +} + +@media screen and (max-width: 425px) { + .sidenav { + width: 100vw; + left: -550px ; + transition: width 0.3s ease; + } + + #toggleButton { + left: 1.4rem; + top: 1rem; + } + + .clear-button, + .random-button { + border: solid 0.1rem var(--border-color1); + border-radius: 0.3rem; + height: calc((100%) / 1.8); + width: auto; + text-align: center; + padding: 0.3rem; + font-family: 'Roboto Mono', monospace; + font-weight: bold; + font-size: 0.5rem; + color: var(--primary-color); + background-color: var(--theme-color3); + transition: box-shadow 0.3s ease, transform 0.2s ease; + margin: 0 0.5rem; /* Add margin to separate buttons */ + } + + .control-button { + transform: scale(1.4); + } +} \ No newline at end of file diff --git a/assets/images/Life's_Mossaic.png b/assets/images/Life's_Mossaic.png new file mode 100644 index 0000000000..cff6551b2b Binary files /dev/null and b/assets/images/Life's_Mossaic.png differ