Compare commits
4 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
5dce3ed955 | ||
|
efd90e9b32 | ||
|
32251898bb | ||
|
c854bf093b |
Before Width: | Height: | Size: 134 KiB |
Before Width: | Height: | Size: 210 KiB |
BIN
Example.jpg
Before Width: | Height: | Size: 872 KiB |
@ -1,38 +0,0 @@
|
|||||||
# Final Evaluation
|
|
||||||
|
|
||||||
## Introduction
|
|
||||||
PotatoPlan is an Inteligent Tractor AI Project and is written in C# using Monogame framework.
|
|
||||||
NuGet Packages used and requeired for the project to work ar as follows:
|
|
||||||
C5
|
|
||||||
Microsoft.ML
|
|
||||||
Microsoft.ML.LightGBM
|
|
||||||
System.Drawing.Common
|
|
||||||
|
|
||||||
In our project agent (tractor) moves on resizable grid, which starting size is dependant on primary screen resolution.
|
|
||||||
The task of the agent is to go through all soil tiles and plant different types of crops, use proper fertilizer and collect crops when fully grown.
|
|
||||||
|
|
||||||
Window can be resized usind WASD. Tractor speed can be changed using UP and DOWN arrow keys, while simulation speed can be changed using LEFT and RIGHT arrow keys.
|
|
||||||
Also house placement can be changed by left clicking on a tile, and get info about the tile by right clicking.
|
|
||||||
|
|
||||||
Apart from Machine Learning Algorithms used in project there are also many different features implemented like:
|
|
||||||
- Using A* algorithm to find an optimal path to previously selected target.
|
|
||||||
- Target is found by scoring system which assign score to a tile based on few factors like production rate or distance.
|
|
||||||
- Dynamically allocated cargo space for each fertilizer based on how often each fertilizer is used.
|
|
||||||
- Day and night cycle and season system.
|
|
||||||
- Using noise map generated for rainfall calculations to draw moving clouds.
|
|
||||||
- ... and few other.
|
|
||||||
|
|
||||||
## Machine Learning Algorithms
|
|
||||||
Project in its current state uses Machine Learning Algorithms to solve 2 problems. Light Gradient-Boosted Trees are used for both problems:
|
|
||||||
1. Choosing a proper fertilizer which should be applied to current tile, based on few variables like nutrients in soil.
|
|
||||||
Applying proper fertilizer boosts production rate of a crop (rate of growth of a crop). This part was done by Oskar Nastały.
|
|
||||||
2. Calculating production rate of a tile based on rainfall and few other variabels. Noise map is generated and used to simulate dynamically changing rainfall.
|
|
||||||
Then once a day AI is used to calculate base production rate multiplier. This part was done by Joel Städe.
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
### Clouds
|
|
||||||
![Clouds](https://git.wmi.amu.edu.pl/s425077/PotatoPlan/raw/Joel-ML/Evaluation_examples/Example_clouds.PNG)
|
|
||||||
|
|
||||||
### UI
|
|
||||||
![UI](https://git.wmi.amu.edu.pl/s425077/PotatoPlan/raw/Joel-ML/Evaluation_examples/Example_UI.PNG)
|
|
Before Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 1.4 MiB |
Before Width: | Height: | Size: 4.8 MiB |
@ -37,18 +37,6 @@
|
|||||||
/processorParam:TextureFormat=Color
|
/processorParam:TextureFormat=Color
|
||||||
/build:BerriesIcon.png
|
/build:BerriesIcon.png
|
||||||
|
|
||||||
#begin Bottom.png
|
|
||||||
/importer:TextureImporter
|
|
||||||
/processor:TextureProcessor
|
|
||||||
/processorParam:ColorKeyColor=255,0,255,255
|
|
||||||
/processorParam:ColorKeyEnabled=True
|
|
||||||
/processorParam:GenerateMipmaps=False
|
|
||||||
/processorParam:PremultiplyAlpha=True
|
|
||||||
/processorParam:ResizeToPowerOfTwo=False
|
|
||||||
/processorParam:MakeSquare=False
|
|
||||||
/processorParam:TextureFormat=Color
|
|
||||||
/build:Bottom.png
|
|
||||||
|
|
||||||
#begin CarronIcon.png
|
#begin CarronIcon.png
|
||||||
/importer:TextureImporter
|
/importer:TextureImporter
|
||||||
/processor:TextureProcessor
|
/processor:TextureProcessor
|
||||||
@ -61,30 +49,6 @@
|
|||||||
/processorParam:TextureFormat=Color
|
/processorParam:TextureFormat=Color
|
||||||
/build:CarronIcon.png;CarrotIcon.png
|
/build:CarronIcon.png;CarrotIcon.png
|
||||||
|
|
||||||
#begin Cloud.png
|
|
||||||
/importer:TextureImporter
|
|
||||||
/processor:TextureProcessor
|
|
||||||
/processorParam:ColorKeyColor=255,0,255,255
|
|
||||||
/processorParam:ColorKeyEnabled=True
|
|
||||||
/processorParam:GenerateMipmaps=False
|
|
||||||
/processorParam:PremultiplyAlpha=True
|
|
||||||
/processorParam:ResizeToPowerOfTwo=False
|
|
||||||
/processorParam:MakeSquare=False
|
|
||||||
/processorParam:TextureFormat=Color
|
|
||||||
/build:Cloud.png
|
|
||||||
|
|
||||||
#begin Clouds.png
|
|
||||||
/importer:TextureImporter
|
|
||||||
/processor:TextureProcessor
|
|
||||||
/processorParam:ColorKeyColor=255,0,255,255
|
|
||||||
/processorParam:ColorKeyEnabled=True
|
|
||||||
/processorParam:GenerateMipmaps=False
|
|
||||||
/processorParam:PremultiplyAlpha=True
|
|
||||||
/processorParam:ResizeToPowerOfTwo=False
|
|
||||||
/processorParam:MakeSquare=False
|
|
||||||
/processorParam:TextureFormat=Color
|
|
||||||
/build:Clouds.png
|
|
||||||
|
|
||||||
#begin CottonIcon.png
|
#begin CottonIcon.png
|
||||||
/importer:TextureImporter
|
/importer:TextureImporter
|
||||||
/processor:TextureProcessor
|
/processor:TextureProcessor
|
||||||
@ -140,18 +104,6 @@
|
|||||||
/processorParam:TextureFormat=Color
|
/processorParam:TextureFormat=Color
|
||||||
/build:house.png
|
/build:house.png
|
||||||
|
|
||||||
#begin Left.png
|
|
||||||
/importer:TextureImporter
|
|
||||||
/processor:TextureProcessor
|
|
||||||
/processorParam:ColorKeyColor=255,0,255,255
|
|
||||||
/processorParam:ColorKeyEnabled=True
|
|
||||||
/processorParam:GenerateMipmaps=False
|
|
||||||
/processorParam:PremultiplyAlpha=True
|
|
||||||
/processorParam:ResizeToPowerOfTwo=False
|
|
||||||
/processorParam:MakeSquare=False
|
|
||||||
/processorParam:TextureFormat=Color
|
|
||||||
/build:Left.png
|
|
||||||
|
|
||||||
#begin MaizeIcon.png
|
#begin MaizeIcon.png
|
||||||
/importer:TextureImporter
|
/importer:TextureImporter
|
||||||
/processor:TextureProcessor
|
/processor:TextureProcessor
|
||||||
@ -236,6 +188,18 @@
|
|||||||
/processorParam:TextureFormat=Color
|
/processorParam:TextureFormat=Color
|
||||||
/build:Plantable.png
|
/build:Plantable.png
|
||||||
|
|
||||||
|
#begin Planted.png
|
||||||
|
/importer:TextureImporter
|
||||||
|
/processor:TextureProcessor
|
||||||
|
/processorParam:ColorKeyColor=255,0,255,255
|
||||||
|
/processorParam:ColorKeyEnabled=True
|
||||||
|
/processorParam:GenerateMipmaps=False
|
||||||
|
/processorParam:PremultiplyAlpha=True
|
||||||
|
/processorParam:ResizeToPowerOfTwo=False
|
||||||
|
/processorParam:MakeSquare=False
|
||||||
|
/processorParam:TextureFormat=Color
|
||||||
|
/build:Planted.png
|
||||||
|
|
||||||
#begin ProgressionBar.png
|
#begin ProgressionBar.png
|
||||||
/importer:TextureImporter
|
/importer:TextureImporter
|
||||||
/processor:TextureProcessor
|
/processor:TextureProcessor
|
||||||
@ -272,30 +236,6 @@
|
|||||||
/processorParam:TextureFormat=Color
|
/processorParam:TextureFormat=Color
|
||||||
/build:PulsesIcon.png
|
/build:PulsesIcon.png
|
||||||
|
|
||||||
#begin rain.png
|
|
||||||
/importer:TextureImporter
|
|
||||||
/processor:TextureProcessor
|
|
||||||
/processorParam:ColorKeyColor=255,0,255,255
|
|
||||||
/processorParam:ColorKeyEnabled=True
|
|
||||||
/processorParam:GenerateMipmaps=False
|
|
||||||
/processorParam:PremultiplyAlpha=True
|
|
||||||
/processorParam:ResizeToPowerOfTwo=False
|
|
||||||
/processorParam:MakeSquare=False
|
|
||||||
/processorParam:TextureFormat=Color
|
|
||||||
/build:rain.png
|
|
||||||
|
|
||||||
#begin Right.png
|
|
||||||
/importer:TextureImporter
|
|
||||||
/processor:TextureProcessor
|
|
||||||
/processorParam:ColorKeyColor=255,0,255,255
|
|
||||||
/processorParam:ColorKeyEnabled=True
|
|
||||||
/processorParam:GenerateMipmaps=False
|
|
||||||
/processorParam:PremultiplyAlpha=True
|
|
||||||
/processorParam:ResizeToPowerOfTwo=False
|
|
||||||
/processorParam:MakeSquare=False
|
|
||||||
/processorParam:TextureFormat=Color
|
|
||||||
/build:Right.png
|
|
||||||
|
|
||||||
#begin SeedOilIcon.png
|
#begin SeedOilIcon.png
|
||||||
/importer:TextureImporter
|
/importer:TextureImporter
|
||||||
/processor:TextureProcessor
|
/processor:TextureProcessor
|
||||||
@ -356,18 +296,6 @@
|
|||||||
/processorParam:TextureFormat=Color
|
/processorParam:TextureFormat=Color
|
||||||
/build:TobaccoIcon.png
|
/build:TobaccoIcon.png
|
||||||
|
|
||||||
#begin Top.png
|
|
||||||
/importer:TextureImporter
|
|
||||||
/processor:TextureProcessor
|
|
||||||
/processorParam:ColorKeyColor=255,0,255,255
|
|
||||||
/processorParam:ColorKeyEnabled=True
|
|
||||||
/processorParam:GenerateMipmaps=False
|
|
||||||
/processorParam:PremultiplyAlpha=True
|
|
||||||
/processorParam:ResizeToPowerOfTwo=False
|
|
||||||
/processorParam:MakeSquare=False
|
|
||||||
/processorParam:TextureFormat=Color
|
|
||||||
/build:Top.png
|
|
||||||
|
|
||||||
#begin Tractor.png
|
#begin Tractor.png
|
||||||
/importer:TextureImporter
|
/importer:TextureImporter
|
||||||
/processor:TextureProcessor
|
/processor:TextureProcessor
|
||||||
@ -404,15 +332,3 @@
|
|||||||
/processorParam:TextureFormat=Color
|
/processorParam:TextureFormat=Color
|
||||||
/build:WheatIcon.png
|
/build:WheatIcon.png
|
||||||
|
|
||||||
#begin WoodBackground.png
|
|
||||||
/importer:TextureImporter
|
|
||||||
/processor:TextureProcessor
|
|
||||||
/processorParam:ColorKeyColor=255,0,255,255
|
|
||||||
/processorParam:ColorKeyEnabled=True
|
|
||||||
/processorParam:GenerateMipmaps=False
|
|
||||||
/processorParam:PremultiplyAlpha=True
|
|
||||||
/processorParam:ResizeToPowerOfTwo=False
|
|
||||||
/processorParam:MakeSquare=False
|
|
||||||
/processorParam:TextureFormat=Color
|
|
||||||
/build:WoodBackground.png
|
|
||||||
|
|
||||||
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 872 KiB |
Before Width: | Height: | Size: 3.8 KiB |
1048576
Game1/Content/ML/Rainfall.csv
@ -1,3 +0,0 @@
|
|||||||
Mean Absolute Error: 0.0108015636096701
|
|
||||||
Mean Squared Error: 0.0434908452113952
|
|
||||||
R Squared: 0.702723944791744
|
|
@ -1,2 +0,0 @@
|
|||||||
Mean Absolute Error: 187.060835104336
|
|
||||||
R Squared: 0.913526230109177
|
|
BIN
Game1/Content/MLmodel
Normal file
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 578 B |
Before Width: | Height: | Size: 578 B |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 5.1 KiB |
Before Width: | Height: | Size: 7.7 KiB |
Before Width: | Height: | Size: 8.9 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 776 B |
BIN
Game1/Content/Planted.png
Normal file
After Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 4.7 MiB |
Before Width: | Height: | Size: 2.8 MiB |
Before Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 8.3 KiB |
Before Width: | Height: | Size: 8.8 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 7.5 KiB |
149
Game1/Game1.cs
@ -2,8 +2,6 @@
|
|||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
using Microsoft.Xna.Framework.Input;
|
using Microsoft.Xna.Framework.Input;
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
|
||||||
using WinForm = System.Windows.Forms;
|
|
||||||
|
|
||||||
namespace Game1
|
namespace Game1
|
||||||
{
|
{
|
||||||
@ -16,17 +14,11 @@ namespace Game1
|
|||||||
SpriteBatch spriteBatch;
|
SpriteBatch spriteBatch;
|
||||||
SpriteFont Bold;
|
SpriteFont Bold;
|
||||||
private Texture2D[] tile = new Texture2D[5];
|
private Texture2D[] tile = new Texture2D[5];
|
||||||
private Texture2D[] tileConnected = new Texture2D[5];
|
|
||||||
private Texture2D[] Crops = new Texture2D[12];
|
private Texture2D[] Crops = new Texture2D[12];
|
||||||
private Texture2D tractor;
|
private Texture2D tractor;
|
||||||
private Texture2D Background;
|
|
||||||
private Texture2D house;
|
private Texture2D house;
|
||||||
private Texture2D markers;
|
private Texture2D markers;
|
||||||
private Texture2D mouseCursor;
|
private Texture2D mouseCursor;
|
||||||
private Texture2D Rain;
|
|
||||||
string directory = Directory.GetCurrentDirectory();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private Texture2D ProgressionBar;
|
private Texture2D ProgressionBar;
|
||||||
private Texture2D ProgressionBarStatus;
|
private Texture2D ProgressionBarStatus;
|
||||||
@ -46,10 +38,6 @@ namespace Game1
|
|||||||
|
|
||||||
MouseState state;
|
MouseState state;
|
||||||
|
|
||||||
private int cloudAnimationSpeed = 3;
|
|
||||||
private int cloudFrame = 0;
|
|
||||||
private int cloudSprite;
|
|
||||||
|
|
||||||
|
|
||||||
public Game1()
|
public Game1()
|
||||||
{
|
{
|
||||||
@ -75,20 +63,15 @@ namespace Game1
|
|||||||
cropTypesNames[10] = "Tobacco";
|
cropTypesNames[10] = "Tobacco";
|
||||||
cropTypesNames[11] = "Wheat";
|
cropTypesNames[11] = "Wheat";
|
||||||
|
|
||||||
Engine.init();
|
|
||||||
Sources.ML_Joel.Engine.initArea();
|
|
||||||
//Sources.ML_Joel.Engine.CreateModel();
|
|
||||||
//Sources.ML_Joel.Engine.CreateModelArea();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//Generates the map with some random values
|
//Generates the map with some random values
|
||||||
inventory.initInventorySystem();
|
inventory.initInventorySystem();
|
||||||
|
input.init(graphics, new Vector2(16,16), 56, 1); //Generates the starting size
|
||||||
|
|
||||||
string path = directory + "Game1/Content/ML/Fertilizer_Prediction.csv";
|
|
||||||
int res = WinForm.Screen.PrimaryScreen.Bounds.Height;
|
|
||||||
input.init(graphics, new Vector2((float)Math.Floor(WinForm.Screen.PrimaryScreen.Bounds.Width/56*0.6f), (float)Math.Floor((WinForm.Screen.PrimaryScreen.Bounds.Height / 56f) - 7)), 56, 0); //Generates the starting size
|
|
||||||
houseUnit.init(input.getTileSize(), input.getSpacing()); //Generates the house position
|
houseUnit.init(input.getTileSize(), input.getSpacing()); //Generates the house position
|
||||||
tractorUnit.init(houseUnit.GetRectangle(), input); //Generates the Tractor
|
tractorUnit.init(houseUnit.GetRectangle(), input); //Generates the Tractor
|
||||||
tractorUnit.updateSizing(input, 0, houseUnit.getVector(), Time); //Updates the first Size of the Tractor
|
tractorUnit.updateSizing(input, 0, houseUnit.getVector(), Time); //Updates the first Size of the Tractor
|
||||||
@ -98,7 +81,7 @@ namespace Game1
|
|||||||
|
|
||||||
|
|
||||||
graphics.PreferredBackBufferWidth = (input.getTileSize() + input.getSpacing()) * (int)input.getSize().X;
|
graphics.PreferredBackBufferWidth = (input.getTileSize() + input.getSpacing()) * (int)input.getSize().X;
|
||||||
graphics.PreferredBackBufferHeight = (input.getTileSize() + input.getSpacing()) * (int)input.getSize().Y + 380;
|
graphics.PreferredBackBufferHeight = (input.getTileSize() + input.getSpacing()) * (int)input.getSize().Y + 300;
|
||||||
graphics.ApplyChanges();
|
graphics.ApplyChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,15 +98,8 @@ namespace Game1
|
|||||||
tile[2] = Content.Load<Texture2D>("Plantable");
|
tile[2] = Content.Load<Texture2D>("Plantable");
|
||||||
tile[3] = Content.Load<Texture2D>("Crop");
|
tile[3] = Content.Load<Texture2D>("Crop");
|
||||||
|
|
||||||
tileConnected[0] = Content.Load<Texture2D>("Left");
|
|
||||||
tileConnected[1] = Content.Load<Texture2D>("Top");
|
|
||||||
tileConnected[2] = Content.Load<Texture2D>("Right");
|
|
||||||
tileConnected[3] = Content.Load<Texture2D>("Bottom");
|
|
||||||
|
|
||||||
Rain = Content.Load<Texture2D>("Clouds");
|
|
||||||
|
|
||||||
|
|
||||||
Background = Content.Load<Texture2D>("WoodBackground");
|
|
||||||
|
|
||||||
|
|
||||||
Crops[0] = Content.Load<Texture2D>("Markers");
|
Crops[0] = Content.Load<Texture2D>("Markers");
|
||||||
@ -175,7 +151,7 @@ namespace Game1
|
|||||||
Time.updateTime(tractorUnit.getSpeed());
|
Time.updateTime(tractorUnit.getSpeed());
|
||||||
|
|
||||||
|
|
||||||
//System.Threading.Thread updatethread = new System.Threading.Thread(new System.Threading.ParameterizedThreadStart(Update));
|
|
||||||
base.Update(gameTime);
|
base.Update(gameTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,73 +161,64 @@ namespace Game1
|
|||||||
GraphicsDevice.Clear(Color.FromNonPremultiplied(255,255,255,140));
|
GraphicsDevice.Clear(Color.FromNonPremultiplied(255,255,255,140));
|
||||||
|
|
||||||
spriteBatch.Begin();
|
spriteBatch.Begin();
|
||||||
|
|
||||||
DrawTiles();
|
DrawTiles();
|
||||||
|
|
||||||
spriteBatch.Draw(markers, new Rectangle((int)tractorUnit.getTargetPosition().X / input.getSpacingTile() * (input.getTileSize() + input.getSpacing()) + input.getTileSize() / 4, (int)tractorUnit.getTargetPosition().Y / input.getSpacingTile() * (input.getTileSize() + input.getSpacing()) + input.getTileSize() / 4, input.getTileSize()/2, input.getTileSize()/2), Color.White);
|
spriteBatch.Draw(markers, new Rectangle((int)tractorUnit.getTargetPosition().X / input.getSpacingTile() * (input.getTileSize() + input.getSpacing()) + input.getTileSize() / 4, (int)tractorUnit.getTargetPosition().Y / input.getSpacingTile() * (input.getTileSize() + input.getSpacing()) + input.getTileSize() / 4, input.getTileSize()/2, input.getTileSize()/2), Color.Green);
|
||||||
for (int i = 0; i < tractorUnit.getPath().getCount() + 1; i++)
|
for (int i = 0; i < tractorUnit.getPath().getCount() + 1; i++)
|
||||||
{
|
{
|
||||||
spriteBatch.Draw(markers, new Rectangle((int)tractorUnit.getPath().getByIndex(i).getCords().X * (input.getSpacingTile()) + input.getTileSize() / 4, (int)tractorUnit.getPath().getByIndex(i).getCords().Y * (input.getSpacingTile()) + input.getTileSize() / 4, input.getTileSize()/2, input.getTileSize()/2), Color.White);
|
spriteBatch.Draw(markers, new Rectangle((int)tractorUnit.getPath().getByIndex(i).getCords().X * (input.getSpacingTile()) + input.getTileSize() / 4, (int)tractorUnit.getPath().getByIndex(i).getCords().Y * (input.getSpacingTile()) + input.getTileSize() / 4, input.getTileSize()/2, input.getTileSize()/2), Color.Green);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
spriteBatch.Draw(house, houseUnit.GetRectangle(), Time.GetTimeOfDay());
|
||||||
spriteBatch.Draw(markers, new Rectangle((int)tractorUnit.getPath().getFinalDest().getCords().X * (input.getSpacingTile()) + Convert.ToInt32(input.getTileSize() / 6), (int)tractorUnit.getPath().getFinalDest().getCords().Y * (input.getSpacingTile()) + Convert.ToInt32(input.getTileSize() / 6), Convert.ToInt32(input.getTileSize() / 1.5), Convert.ToInt32(input.getTileSize() / 1.5)), Color.White); //Draws the current target of the tractor
|
spriteBatch.Draw(markers, new Rectangle((int)tractorUnit.getPath().getFinalDest().getCords().X * (input.getSpacingTile()) + Convert.ToInt32(input.getTileSize() / 6), (int)tractorUnit.getPath().getFinalDest().getCords().Y * (input.getSpacingTile()) + Convert.ToInt32(input.getTileSize() / 6), Convert.ToInt32(input.getTileSize() / 1.5), Convert.ToInt32(input.getTileSize() / 1.5)), Color.Red); //Draws the current target of the tractor
|
||||||
|
spriteBatch.Draw(tractor, new Vector2((int)tractorUnit.getPos().X + input.getTileSize() / 2, (int)tractorUnit.getPos().Y + input.getTileSize() / 2), new Rectangle(0, 0, input.getTileSize(), input.getTileSize()), Time.GetTimeOfDay(), tractorUnit.getRotation(), new Vector2(input.getTileSize() / 2, input.getTileSize() / 2), 1.0f, SpriteEffects.None, 1);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
for (int i = 0; i < 5; i++)
|
for (int i = 0; i < 5; i++)
|
||||||
{
|
{
|
||||||
for (int j = 0; j < 5; j++)
|
spriteBatch.Draw(ProgressionBar, new Rectangle(i * 227, (int)(input.getSize().Y * (input.getTileSize() + input.getSpacing())), 5, 295), Color.White);
|
||||||
{
|
}
|
||||||
spriteBatch.Draw(Background, new Rectangle(i * 512, (int)input.getSize().Y * (input.getTileSize() + input.getSpacing()) + j * 512, 512, 512), Color.FromNonPremultiplied(125, 125, 125, 255));
|
for (int i = 0; i < 15; i++)
|
||||||
}
|
{
|
||||||
|
spriteBatch.Draw(ProgressionBar, new Rectangle(0, (int)(input.getSize().Y * (input.getTileSize() + input.getSpacing())) + i * 20, (int)(input.getSize().X * (input.getTileSize() + input.getSpacing())), 1), Color.White);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < 5; i++)
|
|
||||||
{
|
|
||||||
spriteBatch.Draw(tile[0], new Rectangle(i * 227, (int)(input.getSize().Y * (input.getTileSize() + input.getSpacing())), 5, 500), Color.White);
|
|
||||||
}
|
|
||||||
for (int i = 0; i < 20; i++)
|
|
||||||
{
|
|
||||||
spriteBatch.Draw(tile[0], new Rectangle(0, (int)(input.getSize().Y * (input.getTileSize() + input.getSpacing())) + i * 20, (int)(input.getSize().X * (input.getTileSize() + input.getSpacing())), 1), Color.White);
|
|
||||||
}
|
|
||||||
|
|
||||||
tractorUnit.drawInventory(input, spriteBatch, Bold, inventory.getPredefinedItems());
|
|
||||||
spriteBatch.DrawString(Bold, "Time: ", new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 2), Color.DarkRed);
|
spriteBatch.DrawString(Bold, "Time: ", new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 2), Color.DarkRed);
|
||||||
spriteBatch.DrawString(Bold, "Days " + Time.getDays(), new Vector2(60, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 2), Color.Teal);
|
spriteBatch.DrawString(Bold, "Days " + Time.getDays(), new Vector2(60, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 2), Color.DarkBlue);
|
||||||
spriteBatch.DrawString(Bold, Time.getTimeOfYear(), new Vector2(120, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 2), Color.Teal);
|
|
||||||
spriteBatch.DrawString(Bold, "Day Progression: ", new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 22), Color.DarkRed);
|
spriteBatch.DrawString(Bold, "Day Progression: ", new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 22), Color.DarkRed);
|
||||||
spriteBatch.DrawString(Bold, Time.GetTimeOfDayInt().ToString() + "%", new Vector2(140, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 22), Color.Teal);
|
spriteBatch.DrawString(Bold, Time.GetTimeOfDayInt().ToString() + "%", new Vector2(140, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 22), Color.DarkBlue);
|
||||||
|
|
||||||
spriteBatch.DrawString(Bold, "Tractor Properties:", new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 62), Color.DarkRed);
|
spriteBatch.DrawString(Bold, "Tractor Properties:", new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 62), Color.DarkRed);
|
||||||
|
|
||||||
spriteBatch.DrawString(Bold, "Speed:" + tractorUnit.getSpeed().ToString(), new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 82), Color.Teal);
|
spriteBatch.DrawString(Bold, "Speed:" + tractorUnit.getSpeed().ToString(), new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 82) , Color.DarkBlue);
|
||||||
spriteBatch.DrawString(Bold, "Tractor Position:" + new Vector2((float)Math.Round(tractorUnit.getPos().X / input.getSpacingTile(), 1), (float)Math.Round(tractorUnit.getPos().Y / input.getSpacingTile(), 1)), new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 102), Color.Teal);
|
spriteBatch.DrawString(Bold, "Tractor Position:" + new Vector2((float)Math.Round(tractorUnit.getPos().X / input.getSpacingTile(), 1), (float)Math.Round(tractorUnit.getPos().Y / input.getSpacingTile(), 1)), new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 102), Color.DarkBlue);
|
||||||
spriteBatch.DrawString(Bold, "Tractor Rotation:" + Math.Round(tractorUnit.getRotation(), 2).ToString() + " Degrees", new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 122), Color.Teal);
|
spriteBatch.DrawString(Bold, "Tractor Rotation:" + Math.Round(tractorUnit.getRotation(), 2).ToString() + " Degrees", new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 122), Color.DarkBlue);
|
||||||
spriteBatch.DrawString(Bold, "Tractor Speed:" + tractorUnit.getTractorSpeed().ToString(), new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 142), Color.Teal);
|
spriteBatch.DrawString(Bold, "Tractor Speed:" + tractorUnit.getTractorSpeed().ToString(), new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 142), Color.DarkBlue);
|
||||||
spriteBatch.DrawString(Bold, "Tractor Target:" + tractorUnit.getPath().getFinalDest().getCords().ToString(), new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 162), Color.Teal);
|
spriteBatch.DrawString(Bold, "Tractor Target:" + tractorUnit.getPath().getFinalDest().getCords().ToString(), new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 162), Color.DarkBlue);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
spriteBatch.DrawString(Bold, "Map Properties:", new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 202), Color.DarkRed);
|
spriteBatch.DrawString(Bold, "Map Properties:", new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 202), Color.DarkRed);
|
||||||
spriteBatch.DrawString(Bold, "Tile Size:" + input.getTileSize().ToString() + "pix", new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 222), Color.Teal); //Draws the tile size
|
spriteBatch.DrawString(Bold, "Tile Size:" + input.getTileSize().ToString() + "pix", new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 222), Color.DarkBlue); //Draws the tile size
|
||||||
spriteBatch.DrawString(Bold, "Matrix Size: " + input.getSize().X.ToString() + " X " + input.getSize().Y.ToString(), new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 242), Color.Teal);
|
spriteBatch.DrawString(Bold, "Matrix Size: " + input.getSize().X.ToString() + " X " + input.getSize().Y.ToString(), new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 242), Color.DarkBlue);
|
||||||
spriteBatch.DrawString(Bold, "House Position: " + houseUnit.getVector() / input.getSpacingTile(), new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 262), Color.Teal);
|
spriteBatch.DrawString(Bold, "House Position: " + houseUnit.getVector() / input.getSpacingTile(), new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 262), Color.DarkBlue);
|
||||||
tractorUnit.getFarm().drawWeatherInformation(spriteBatch, Bold, input);
|
|
||||||
spriteBatch.DrawString(Bold, "Total Weight: ", new Vector2(700, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 182), Color.DarkRed);
|
spriteBatch.DrawString(Bold, "Total Weight: ", new Vector2(700, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 182), Color.DarkRed);
|
||||||
spriteBatch.DrawString(Bold, "(" + tractorUnit.getInventory().getWeight() + "/" + tractorUnit.getInventory().getMaxWeight() + ")", new Vector2(800, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 182), Color.Teal);
|
spriteBatch.DrawString(Bold, "(" + tractorUnit.getInventory().getWeight() + "/" + tractorUnit.getInventory().getMaxWeight() + ")", new Vector2(800, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 182), Color.DarkBlue);
|
||||||
|
|
||||||
|
tractorUnit.drawInventory(input, spriteBatch, Bold, inventory.getPredefinedItems());
|
||||||
|
|
||||||
|
InspectTile();
|
||||||
|
|
||||||
spriteBatch.Draw(mouseCursor, new Rectangle((int)mousePosition.X, (int)mousePosition.Y, 14, 21), Color.White);
|
spriteBatch.Draw(mouseCursor, new Rectangle((int)mousePosition.X, (int)mousePosition.Y, 14, 21), Color.White);
|
||||||
|
|
||||||
spriteBatch.End();
|
spriteBatch.End();
|
||||||
|
|
||||||
spriteBatch.Begin();
|
|
||||||
InspectTile();
|
|
||||||
spriteBatch.End();
|
|
||||||
base.Draw(gameTime);
|
base.Draw(gameTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -262,38 +229,11 @@ namespace Game1
|
|||||||
{
|
{
|
||||||
for (int j = 0; j < input.getSize().Y; j++)
|
for (int j = 0; j < input.getSize().Y; j++)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
Rectangle tilePos = new Rectangle(i * (input.getSpacingTile()), j * (input.getSpacingTile()), input.getTileSize(), input.getTileSize());
|
Rectangle tilePos = new Rectangle(i * (input.getSpacingTile()), j * (input.getSpacingTile()), input.getTileSize(), input.getTileSize());
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
spriteBatch.Draw(tile[tractorUnit.getFarm().getCrop(i, j).getStatus()], tilePos, Time.GetTimeOfDay());
|
spriteBatch.Draw(tile[tractorUnit.getFarm().getCrop(i, j).getStatus()], tilePos, Time.GetTimeOfDay());
|
||||||
if (i > 0)
|
|
||||||
{
|
|
||||||
if (tractorUnit.getFarm().getCrop(i - 1, j).getStatus() == 2 || tractorUnit.getFarm().getCrop(i - 1, j).getStatus() == 3)
|
|
||||||
{
|
|
||||||
spriteBatch.Draw(tileConnected[0], tilePos, Time.GetTimeOfDay());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (j > 0)
|
|
||||||
{
|
|
||||||
if (tractorUnit.getFarm().getCrop(i, j - 1).getStatus() == 2 || tractorUnit.getFarm().getCrop(i, j - 1).getStatus() == 3)
|
|
||||||
{
|
|
||||||
spriteBatch.Draw(tileConnected[1], tilePos, Time.GetTimeOfDay());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (i < input.getSize().X)
|
|
||||||
{
|
|
||||||
if (tractorUnit.getFarm().getCrop(i + 1, j).getStatus() == 2 || tractorUnit.getFarm().getCrop(i + 1, j).getStatus() == 3)
|
|
||||||
{
|
|
||||||
spriteBatch.Draw(tileConnected[2], tilePos, Time.GetTimeOfDay());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (j < input.getSize().Y)
|
|
||||||
{
|
|
||||||
if (tractorUnit.getFarm().getCrop(i, j + 1).getStatus() == 2 || tractorUnit.getFarm().getCrop(i, j + 1).getStatus() == 3)
|
|
||||||
{
|
|
||||||
spriteBatch.Draw(tileConnected[3], tilePos, Time.GetTimeOfDay());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (tilePos.Intersects(mousePosition))
|
if (tilePos.Intersects(mousePosition))
|
||||||
{
|
{
|
||||||
spriteBatch.Draw(tile[tractorUnit.getFarm().getCrop(i, j).getStatus()], tilePos, Color.FromNonPremultiplied(0, 0, 20, 40));
|
spriteBatch.Draw(tile[tractorUnit.getFarm().getCrop(i, j).getStatus()], tilePos, Color.FromNonPremultiplied(0, 0, 20, 40));
|
||||||
@ -320,7 +260,7 @@ namespace Game1
|
|||||||
if ((tractorUnit.getFarm().getCrop(i, j).getStatus() == 3))
|
if ((tractorUnit.getFarm().getCrop(i, j).getStatus() == 3))
|
||||||
{
|
{
|
||||||
spriteBatch.Draw(ProgressionBar, new Rectangle(i * (input.getSpacingTile()) + input.getTileSize() - input.getTileSize() / 3, j * (input.getSpacingTile()), input.getTileSize() / 3, input.getTileSize()), Color.White);
|
spriteBatch.Draw(ProgressionBar, new Rectangle(i * (input.getSpacingTile()) + input.getTileSize() - input.getTileSize() / 3, j * (input.getSpacingTile()), input.getTileSize() / 3, input.getTileSize()), Color.White);
|
||||||
spriteBatch.Draw(ProgressionBarStatus, new Rectangle(i * (input.getSpacingTile()) + input.getTileSize() - input.getTileSize() / 4, j * (input.getSpacingTile()) + input.getTileSize() / 3, input.getTileSize() / 4, tractorUnit.getFarm().getCrop(i, j).getCropTimerBar((input.getTileSize())) + 1), new Color(tractorUnit.getFarm().getCrop(i, j).getColour()));
|
spriteBatch.Draw(ProgressionBarStatus, new Rectangle(i * (input.getSpacingTile()) + input.getTileSize() - input.getTileSize() / 4, j * (input.getSpacingTile()) + input.getTileSize() / 3, input.getTileSize() / 4, tractorUnit.getFarm().getCrop(i, j).getCropTimerBar((input.getTileSize())) + 1), Color.White);
|
||||||
}
|
}
|
||||||
spriteBatch.Draw(Crops[tractorUnit.getFarm().getCrop(i, j).getCropType()], new Rectangle((int)(i * (input.getSpacingTile()) + input.getTileSize() - input.getTileSize() / 2.5), j * (input.getSpacingTile()), (int)(input.getTileSize() / 2.5), input.getTileSize() / 3), Color.White);
|
spriteBatch.Draw(Crops[tractorUnit.getFarm().getCrop(i, j).getCropType()], new Rectangle((int)(i * (input.getSpacingTile()) + input.getTileSize() - input.getTileSize() / 2.5), j * (input.getSpacingTile()), (int)(input.getTileSize() / 2.5), input.getTileSize() / 3), Color.White);
|
||||||
}
|
}
|
||||||
@ -328,23 +268,12 @@ namespace Game1
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
spriteBatch.Draw(house, houseUnit.GetRectangle(), Time.GetTimeOfDay());
|
|
||||||
spriteBatch.Draw(tractor, new Vector2((int)tractorUnit.getPos().X + input.getTileSize() / 2, (int)tractorUnit.getPos().Y + input.getTileSize() / 2), new Rectangle(0, 0, input.getTileSize(), input.getTileSize()), Time.GetTimeOfDay(), tractorUnit.getRotation(), new Vector2(input.getTileSize() / 2, input.getTileSize() / 2), 1.0f, SpriteEffects.None, 1);
|
|
||||||
|
|
||||||
for (int i = -1; i < input.getSize().X + 1; i++) //Draw the tiles
|
|
||||||
{
|
|
||||||
for (int j = -1; j < input.getSize().Y + 1; j++)
|
|
||||||
{
|
|
||||||
spriteBatch.Draw(Rain, tractorUnit.getFarm().getRainPosition(input.getTileSize(), i, j, input.getSize()), tractorUnit.getFarm().getDestinationRectangle(i, j, input.getSize()), tractorUnit.getFarm().getRainAmount(i, j, Time.GetTimeOfDay(), input.getSize()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void InspectTile()
|
public void InspectTile()
|
||||||
{
|
{
|
||||||
spriteBatch.DrawString(Bold, "Crop:", new Vector2(240, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 2), Color.DarkRed);
|
spriteBatch.DrawString(Bold, "Crop:", new Vector2(240, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 2), Color.DarkRed);
|
||||||
spriteBatch.DrawString(Bold, "Selected tile: (" + x.ToString() + ", " + y.ToString() + ")", new Vector2(240, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 22), Color.Teal);
|
spriteBatch.DrawString(Bold, "Selected tile: (" + x.ToString() + ", " + y.ToString() + ")", new Vector2(240, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 22), Color.DarkBlue);
|
||||||
tractorUnit.getFarm().getCrop(x, y).Inspect(input.getTileSize(), input.getSpacing(), Bold, new SpriteBatch(GraphicsDevice), cropTypesNames);
|
tractorUnit.getFarm().getCrop(x, y).Inspect(input.getTileSize(), input.getSpacing(), Bold, new SpriteBatch(GraphicsDevice), cropTypesNames);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -87,18 +87,8 @@
|
|||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="Sources\Crops\CropType.cs" />
|
<Compile Include="Sources\Crops\CropType.cs" />
|
||||||
<Compile Include="Sources\Crops\CropTypesHolder.cs" />
|
<Compile Include="Sources\Crops\CropTypesHolder.cs" />
|
||||||
<Compile Include="Sources\Crops\PerlinNoise.cs" />
|
|
||||||
<Compile Include="Sources\Crops\SoilProperties.cs" />
|
<Compile Include="Sources\Crops\SoilProperties.cs" />
|
||||||
<Compile Include="Sources\ML\Engine.cs" />
|
|
||||||
<Compile Include="Sources\ML_Joel\DataModel\InputArea.cs" />
|
|
||||||
<Compile Include="Sources\ML_Joel\DataModel\Input.cs" />
|
|
||||||
<Compile Include="Sources\ML_Joel\DataModel\OutputArea.cs" />
|
|
||||||
<Compile Include="Sources\ML_Joel\DataModel\Output.cs" />
|
|
||||||
<Compile Include="Sources\ML_Joel\Engine.cs" />
|
|
||||||
<Compile Include="Sources\ML_Joel\Model.cs" />
|
|
||||||
<Compile Include="Sources\Objects\DayNightCycle.cs" />
|
<Compile Include="Sources\Objects\DayNightCycle.cs" />
|
||||||
<Compile Include="Sources\Objects\Fertilizer.cs" />
|
|
||||||
<Compile Include="Sources\Objects\FertilizerHolder.cs" />
|
|
||||||
<Compile Include="Sources\Objects\HandleRotation.cs" />
|
<Compile Include="Sources\Objects\HandleRotation.cs" />
|
||||||
<Compile Include="Properties\Resources.Designer.cs">
|
<Compile Include="Properties\Resources.Designer.cs">
|
||||||
<AutoGen>True</AutoGen>
|
<AutoGen>True</AutoGen>
|
||||||
@ -122,6 +112,7 @@
|
|||||||
<Compile Include="Sources\Pathing\A-Star\PathSaver\MinHeap.cs" />
|
<Compile Include="Sources\Pathing\A-Star\PathSaver\MinHeap.cs" />
|
||||||
<Compile Include="Sources\Pathing\A-Star\PathSaver\Nodes.cs" />
|
<Compile Include="Sources\Pathing\A-Star\PathSaver\Nodes.cs" />
|
||||||
<Compile Include="Sources\Pathing\A-Star\PathSaver\Path.cs" />
|
<Compile Include="Sources\Pathing\A-Star\PathSaver\Path.cs" />
|
||||||
|
<Compile Include="Sources\Pathing\A-Star\PathSaver\PriorityQueue.cs" />
|
||||||
<Compile Include="Sources\Controlls\Controller.cs" />
|
<Compile Include="Sources\Controlls\Controller.cs" />
|
||||||
<Compile Include="Sources\Pathing\PQEntry.cs" />
|
<Compile Include="Sources\Pathing\PQEntry.cs" />
|
||||||
<Compile Include="Sources\Pathing\PriorityQueueC5.cs" />
|
<Compile Include="Sources\Pathing\PriorityQueueC5.cs" />
|
||||||
@ -136,7 +127,6 @@
|
|||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="System.Numerics" />
|
<Reference Include="System.Numerics" />
|
||||||
<Reference Include="System.Windows.Forms" />
|
|
||||||
<Reference Include="System.Xml" />
|
<Reference Include="System.Xml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@ -167,15 +157,9 @@
|
|||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="LibNoise">
|
|
||||||
<Version>0.2.0</Version>
|
|
||||||
</PackageReference>
|
|
||||||
<PackageReference Include="LightGBM">
|
<PackageReference Include="LightGBM">
|
||||||
<Version>2.3.1</Version>
|
<Version>2.3.1</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.CodeAnalysis.Common">
|
|
||||||
<Version>3.6.0</Version>
|
|
||||||
</PackageReference>
|
|
||||||
<PackageReference Include="Microsoft.ML">
|
<PackageReference Include="Microsoft.ML">
|
||||||
<Version>1.4.0</Version>
|
<Version>1.4.0</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
@ -197,9 +181,6 @@
|
|||||||
<PackageReference Include="System.Collections.Immutable">
|
<PackageReference Include="System.Collections.Immutable">
|
||||||
<Version>1.7.0</Version>
|
<Version>1.7.0</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="System.Drawing.Common">
|
|
||||||
<Version>4.7.0</Version>
|
|
||||||
</PackageReference>
|
|
||||||
<PackageReference Include="System.Memory">
|
<PackageReference Include="System.Memory">
|
||||||
<Version>4.5.4</Version>
|
<Version>4.5.4</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
@ -2,8 +2,6 @@
|
|||||||
using Microsoft.Xna.Framework.Input;
|
using Microsoft.Xna.Framework.Input;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
using System;
|
using System;
|
||||||
using System.Drawing;
|
|
||||||
using WinForm = System.Windows.Forms;
|
|
||||||
|
|
||||||
class Controller
|
class Controller
|
||||||
{
|
{
|
||||||
@ -19,7 +17,7 @@ class Controller
|
|||||||
public Vector2 updateWindow(int tileSize, int Spacing, Vector2 Size)
|
public Vector2 updateWindow(int tileSize, int Spacing, Vector2 Size)
|
||||||
{
|
{
|
||||||
KeyboardState state = Keyboard.GetState();
|
KeyboardState state = Keyboard.GetState();
|
||||||
if (state.IsKeyDown(Keys.D) && Size.X < Math.Floor(WinForm.Screen.PrimaryScreen.Bounds.Width / (float)tileSize))
|
if (state.IsKeyDown(Keys.D) && Size.X < 99)
|
||||||
{
|
{
|
||||||
Size.X++;
|
Size.X++;
|
||||||
graphics.PreferredBackBufferWidth = (tileSize + Spacing) * (int)Size.X - Spacing;
|
graphics.PreferredBackBufferWidth = (tileSize + Spacing) * (int)Size.X - Spacing;
|
||||||
@ -31,16 +29,16 @@ class Controller
|
|||||||
graphics.PreferredBackBufferWidth = (tileSize + Spacing) * (int)Size.X - Spacing;
|
graphics.PreferredBackBufferWidth = (tileSize + Spacing) * (int)Size.X - Spacing;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state.IsKeyDown(Keys.W) && Size.Y < Math.Floor(WinForm.Screen.PrimaryScreen.Bounds.Height / (float)tileSize) - 7)
|
if (state.IsKeyDown(Keys.W) && Size.Y < 20)
|
||||||
{
|
{
|
||||||
Size.Y++;
|
Size.Y++;
|
||||||
graphics.PreferredBackBufferHeight = (tileSize + Spacing) * (int)Size.Y - Spacing + 380;
|
graphics.PreferredBackBufferHeight = (tileSize + Spacing) * (int)Size.Y - Spacing + 300;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state.IsKeyDown(Keys.S) && Size.Y > 2)
|
if (state.IsKeyDown(Keys.S) && Size.Y > 2)
|
||||||
{
|
{
|
||||||
Size.Y--;
|
Size.Y--;
|
||||||
graphics.PreferredBackBufferHeight = (tileSize + Spacing) * (int)Size.Y - Spacing + 380;
|
graphics.PreferredBackBufferHeight = (tileSize + Spacing) * (int)Size.Y - Spacing + 300;
|
||||||
}
|
}
|
||||||
return Size;
|
return Size;
|
||||||
}
|
}
|
||||||
|
@ -11,17 +11,12 @@ class CropTypes
|
|||||||
|
|
||||||
public string[] soilType = new string[3];
|
public string[] soilType = new string[3];
|
||||||
public int[] Times = new int[3];
|
public int[] Times = new int[3];
|
||||||
public string CropName;
|
|
||||||
public string[] Season = new string[5];
|
|
||||||
public float Temparature;
|
public float Temparature;
|
||||||
public float Humidity;
|
public float Humidity;
|
||||||
public float Moisture;
|
public float Moisture;
|
||||||
public float Nitrogen;
|
public float Nitrogen;
|
||||||
public float Potassium;
|
public float Potassium;
|
||||||
public float Phosphorous;
|
public float Phosphorous;
|
||||||
public float Area;
|
|
||||||
public int AreaMin;
|
|
||||||
public int AreaMax;
|
|
||||||
|
|
||||||
|
|
||||||
public CropTypes()
|
public CropTypes()
|
||||||
|
@ -16,7 +16,6 @@ class CropTypesHolder
|
|||||||
cropTypes[0].soilType[0] = "None";
|
cropTypes[0].soilType[0] = "None";
|
||||||
cropTypes[0].soilType[1] = null;
|
cropTypes[0].soilType[1] = null;
|
||||||
cropTypes[0].soilType[2] = null;
|
cropTypes[0].soilType[2] = null;
|
||||||
cropTypes[0].CropName = "None";
|
|
||||||
cropTypes[0].Temparature = 0f;
|
cropTypes[0].Temparature = 0f;
|
||||||
cropTypes[0].Humidity = 0f;
|
cropTypes[0].Humidity = 0f;
|
||||||
cropTypes[0].Moisture = 0f;
|
cropTypes[0].Moisture = 0f;
|
||||||
@ -29,17 +28,12 @@ class CropTypesHolder
|
|||||||
cropTypes[1].soilType[0] = "Sandy";
|
cropTypes[1].soilType[0] = "Sandy";
|
||||||
cropTypes[1].soilType[1] = null;
|
cropTypes[1].soilType[1] = null;
|
||||||
cropTypes[1].soilType[2] = null;
|
cropTypes[1].soilType[2] = null;
|
||||||
cropTypes[1].CropName = "Barley";
|
|
||||||
cropTypes[1].Temparature = 30.1f;
|
cropTypes[1].Temparature = 30.1f;
|
||||||
cropTypes[1].Humidity = 59.0f;
|
cropTypes[1].Humidity = 59.0f;
|
||||||
cropTypes[1].Moisture = 41.7f;
|
cropTypes[1].Moisture = 41.7f;
|
||||||
cropTypes[1].Nitrogen = 21 + 12.6f;
|
cropTypes[1].Nitrogen = 12.6f;
|
||||||
cropTypes[1].Potassium = 10 + 5.3f;
|
cropTypes[1].Potassium = 5.3f;
|
||||||
cropTypes[1].Phosphorous = 20 + 26.0f;
|
cropTypes[1].Phosphorous = 26.0f;
|
||||||
cropTypes[1].Season[0] = "Spring";
|
|
||||||
cropTypes[1].Season[1] = "Autumn";
|
|
||||||
cropTypes[1].AreaMin = 1;
|
|
||||||
cropTypes[1].AreaMax = 8000;
|
|
||||||
|
|
||||||
|
|
||||||
// Cotton
|
// Cotton
|
||||||
@ -50,38 +44,24 @@ class CropTypesHolder
|
|||||||
cropTypes[2].Times[1] = 4;
|
cropTypes[2].Times[1] = 4;
|
||||||
cropTypes[2].soilType[2] = "Loamy";
|
cropTypes[2].soilType[2] = "Loamy";
|
||||||
cropTypes[2].Times[2] = 3;
|
cropTypes[2].Times[2] = 3;
|
||||||
cropTypes[2].CropName = "Cotton";
|
|
||||||
cropTypes[2].Temparature = 30.4f;
|
cropTypes[2].Temparature = 30.4f;
|
||||||
cropTypes[2].Humidity = 59.6f;
|
cropTypes[2].Humidity = 59.6f;
|
||||||
cropTypes[2].Moisture = 63.2f;
|
cropTypes[2].Moisture = 63.2f;
|
||||||
cropTypes[2].Nitrogen = 21 + 16.4f;
|
cropTypes[2].Nitrogen = 16.4f;
|
||||||
cropTypes[2].Potassium = 10 + 3.3f;
|
cropTypes[2].Potassium = 3.3f;
|
||||||
cropTypes[2].Phosphorous = 20 + 23.8f;
|
cropTypes[2].Phosphorous = 23.8f;
|
||||||
cropTypes[2].Season[0] = "Spring";
|
|
||||||
cropTypes[2].Season[1] = "Autumn";
|
|
||||||
cropTypes[2].Season[2] = "Whole Year";
|
|
||||||
cropTypes[2].AreaMin = 1;
|
|
||||||
cropTypes[2].AreaMax = 199000;
|
|
||||||
|
|
||||||
// Ground Nuts
|
// Ground Nuts
|
||||||
cropTypes[3] = new CropTypes();
|
cropTypes[3] = new CropTypes();
|
||||||
cropTypes[3].soilType[0] = "Red";
|
cropTypes[3].soilType[0] = "Red";
|
||||||
cropTypes[3].soilType[1] = null;
|
cropTypes[3].soilType[1] = null;
|
||||||
cropTypes[3].soilType[2] = null;
|
cropTypes[3].soilType[2] = null;
|
||||||
cropTypes[3].CropName = "Ground Nuts";
|
|
||||||
cropTypes[3].Temparature = 30.1f;
|
cropTypes[3].Temparature = 30.1f;
|
||||||
cropTypes[3].Humidity = 59.1f;
|
cropTypes[3].Humidity = 59.1f;
|
||||||
cropTypes[3].Moisture = 33.1f;
|
cropTypes[3].Moisture = 33.1f;
|
||||||
cropTypes[3].Nitrogen = 21 + 23.3f;
|
cropTypes[3].Nitrogen = 23.3f;
|
||||||
cropTypes[3].Potassium = 10 + 2.0f;
|
cropTypes[3].Potassium = 2.0f;
|
||||||
cropTypes[3].Phosphorous = 20 + 21.6f;
|
cropTypes[3].Phosphorous = 21.6f;
|
||||||
cropTypes[3].Season[0] = "Spring";
|
|
||||||
cropTypes[3].Season[1] = "Autumn";
|
|
||||||
cropTypes[3].Season[2] = "Whole Year";
|
|
||||||
cropTypes[3].Season[3] = "Winter";
|
|
||||||
cropTypes[3].Season[4] = "Summer";
|
|
||||||
cropTypes[3].AreaMin = 1;
|
|
||||||
cropTypes[3].AreaMax = 147000;
|
|
||||||
|
|
||||||
|
|
||||||
// Maize
|
// Maize
|
||||||
@ -89,20 +69,12 @@ class CropTypesHolder
|
|||||||
cropTypes[4].soilType[0] = "Sandy";
|
cropTypes[4].soilType[0] = "Sandy";
|
||||||
cropTypes[4].soilType[1] = null;
|
cropTypes[4].soilType[1] = null;
|
||||||
cropTypes[4].soilType[2] = null;
|
cropTypes[4].soilType[2] = null;
|
||||||
cropTypes[4].CropName = "Maize";
|
|
||||||
cropTypes[4].Temparature = 29.0f;
|
cropTypes[4].Temparature = 29.0f;
|
||||||
cropTypes[4].Humidity = 57.3f;
|
cropTypes[4].Humidity = 57.3f;
|
||||||
cropTypes[4].Moisture = 42.2f;
|
cropTypes[4].Moisture = 42.2f;
|
||||||
cropTypes[4].Nitrogen = 21 + 18.3f;
|
cropTypes[4].Nitrogen = 18.3f;
|
||||||
cropTypes[4].Potassium = 10 + 5.7f;
|
cropTypes[4].Potassium = 5.7f;
|
||||||
cropTypes[4].Phosphorous = 20 + 18.7f;
|
cropTypes[4].Phosphorous = 18.7f;
|
||||||
cropTypes[4].Season[0] = "Spring";
|
|
||||||
cropTypes[4].Season[1] = "Autumn";
|
|
||||||
cropTypes[4].Season[2] = "Whole Year";
|
|
||||||
cropTypes[4].Season[3] = "Winter";
|
|
||||||
cropTypes[4].Season[4] = "Summer";
|
|
||||||
cropTypes[4].AreaMin = 1;
|
|
||||||
cropTypes[4].AreaMax = 73000;
|
|
||||||
|
|
||||||
// Millets
|
// Millets
|
||||||
cropTypes[5] = new CropTypes();
|
cropTypes[5] = new CropTypes();
|
||||||
@ -111,71 +83,48 @@ class CropTypesHolder
|
|||||||
cropTypes[5].soilType[1] = "Black";
|
cropTypes[5].soilType[1] = "Black";
|
||||||
cropTypes[5].Times[0] = 4;
|
cropTypes[5].Times[0] = 4;
|
||||||
cropTypes[5].soilType[2] = null;
|
cropTypes[5].soilType[2] = null;
|
||||||
cropTypes[5].CropName = "Millets";
|
|
||||||
cropTypes[5].Temparature = 29.5f;
|
cropTypes[5].Temparature = 29.5f;
|
||||||
cropTypes[5].Humidity = 57.3f;
|
cropTypes[5].Humidity = 57.3f;
|
||||||
cropTypes[5].Moisture = 38.5f;
|
cropTypes[5].Moisture = 38.5f;
|
||||||
cropTypes[5].Nitrogen = 21 + 23.2f;
|
cropTypes[5].Nitrogen = 23.2f;
|
||||||
cropTypes[5].Potassium = 10 + 0.1f;
|
cropTypes[5].Potassium = 0.1f;
|
||||||
cropTypes[5].Phosphorous = 20 + 14.4f;
|
cropTypes[5].Phosphorous = 14.4f;
|
||||||
cropTypes[5].Season[0] = "Spring";
|
|
||||||
cropTypes[5].Season[1] = "Autumn";
|
|
||||||
cropTypes[5].Season[2] = "Whole Year";
|
|
||||||
cropTypes[5].AreaMin = 1;
|
|
||||||
cropTypes[5].AreaMax = 59000;
|
|
||||||
|
|
||||||
//Oil Seeds
|
//Oil Seeds
|
||||||
cropTypes[6] = new CropTypes();
|
cropTypes[6] = new CropTypes();
|
||||||
cropTypes[6].soilType[0] = "Black";
|
cropTypes[6].soilType[0] = "Black";
|
||||||
cropTypes[6].soilType[1] = null;
|
cropTypes[6].soilType[1] = null;
|
||||||
cropTypes[6].soilType[2] = null;
|
cropTypes[6].soilType[2] = null;
|
||||||
cropTypes[6].CropName = "Oil Seeds";
|
|
||||||
cropTypes[6].Temparature = 30.3f;
|
cropTypes[6].Temparature = 30.3f;
|
||||||
cropTypes[6].Humidity = 59.1f;
|
cropTypes[6].Humidity = 59.1f;
|
||||||
cropTypes[6].Moisture = 32.1f;
|
cropTypes[6].Moisture = 32.1f;
|
||||||
cropTypes[6].Nitrogen = 21 + 19.0f;
|
cropTypes[6].Nitrogen = 19.0f;
|
||||||
cropTypes[6].Potassium = 10 + 2.3f;
|
cropTypes[6].Potassium = 2.3f;
|
||||||
cropTypes[6].Phosphorous = 20 + 17.3f;
|
cropTypes[6].Phosphorous = 17.3f;
|
||||||
cropTypes[6].Season[0] = "Whole Year";
|
|
||||||
cropTypes[6].AreaMin = 25;
|
|
||||||
cropTypes[6].AreaMax = 25000;
|
|
||||||
|
|
||||||
//Paddys
|
//Paddys
|
||||||
cropTypes[7] = new CropTypes();
|
cropTypes[7] = new CropTypes();
|
||||||
cropTypes[7].soilType[0] = "Clayey";
|
cropTypes[7].soilType[0] = "Clayey";
|
||||||
cropTypes[7].soilType[1] = null;
|
cropTypes[7].soilType[1] = null;
|
||||||
cropTypes[7].soilType[2] = null;
|
cropTypes[7].soilType[2] = null;
|
||||||
cropTypes[7].CropName = "Paddys";
|
|
||||||
cropTypes[7].Temparature = 31.2f;
|
cropTypes[7].Temparature = 31.2f;
|
||||||
cropTypes[7].Humidity = 60.4f;
|
cropTypes[7].Humidity = 60.4f;
|
||||||
cropTypes[7].Moisture = 41.5f;
|
cropTypes[7].Moisture = 41.5f;
|
||||||
cropTypes[7].Nitrogen = 21 + 20.8f;
|
cropTypes[7].Nitrogen = 20.8f;
|
||||||
cropTypes[7].Potassium = 10 + 3.7f;
|
cropTypes[7].Potassium = 3.7f;
|
||||||
cropTypes[7].Phosphorous = 20 + 16.3f;
|
cropTypes[7].Phosphorous = 16.3f;
|
||||||
cropTypes[7].Season[0] = "Autumn";
|
|
||||||
cropTypes[7].Season[1] = "Winter";
|
|
||||||
cropTypes[7].Season[2] = "Summer";
|
|
||||||
cropTypes[7].AreaMin = 200;
|
|
||||||
cropTypes[7].AreaMax = 270000;
|
|
||||||
|
|
||||||
//Pulses
|
//Pulses
|
||||||
cropTypes[8] = new CropTypes();
|
cropTypes[8] = new CropTypes();
|
||||||
cropTypes[8].soilType[0] = "Clayey";
|
cropTypes[8].soilType[0] = "Clayey";
|
||||||
cropTypes[8].soilType[1] = null;
|
cropTypes[8].soilType[1] = null;
|
||||||
cropTypes[8].soilType[2] = null;
|
cropTypes[8].soilType[2] = null;
|
||||||
cropTypes[8].CropName = "Pulses";
|
|
||||||
cropTypes[8].Temparature = 27.8f;
|
cropTypes[8].Temparature = 27.8f;
|
||||||
cropTypes[8].Humidity = 54.9f;
|
cropTypes[8].Humidity = 54.9f;
|
||||||
cropTypes[8].Moisture = 34.1f;
|
cropTypes[8].Moisture = 34.1f;
|
||||||
cropTypes[8].Nitrogen = 21 + 18.4f;
|
cropTypes[8].Nitrogen = 18.4f;
|
||||||
cropTypes[8].Potassium = 10 + 4.2f;
|
cropTypes[8].Potassium = 4.2f;
|
||||||
cropTypes[8].Phosphorous = 20 + 17.5f;
|
cropTypes[8].Phosphorous = 17.5f;
|
||||||
cropTypes[8].Season[0] = "Spring";
|
|
||||||
cropTypes[8].Season[1] = "Autumn";
|
|
||||||
cropTypes[8].Season[2] = "Whole Year";
|
|
||||||
cropTypes[8].Season[3] = "Summer";
|
|
||||||
cropTypes[8].AreaMin = 40;
|
|
||||||
cropTypes[8].AreaMax = 140000;
|
|
||||||
|
|
||||||
//Sugarcane
|
//Sugarcane
|
||||||
cropTypes[9] = new CropTypes();
|
cropTypes[9] = new CropTypes();
|
||||||
@ -184,19 +133,12 @@ class CropTypesHolder
|
|||||||
cropTypes[9].soilType[1] = "Black";
|
cropTypes[9].soilType[1] = "Black";
|
||||||
cropTypes[9].Times[0] = 4;
|
cropTypes[9].Times[0] = 4;
|
||||||
cropTypes[9].soilType[2] = null;
|
cropTypes[9].soilType[2] = null;
|
||||||
cropTypes[9].CropName = "Sugarcane";
|
|
||||||
cropTypes[9].Temparature = 30.0f;
|
cropTypes[9].Temparature = 30.0f;
|
||||||
cropTypes[9].Humidity = 58.6f;
|
cropTypes[9].Humidity = 58.6f;
|
||||||
cropTypes[9].Moisture = 51.2f;
|
cropTypes[9].Moisture = 51.2f;
|
||||||
cropTypes[9].Nitrogen = 21 + 14.6f;
|
cropTypes[9].Nitrogen = 14.6f;
|
||||||
cropTypes[9].Potassium = 10 + 4.2f;
|
cropTypes[9].Potassium = 4.2f;
|
||||||
cropTypes[9].Phosphorous = 20 + 17.6f;
|
cropTypes[9].Phosphorous = 17.6f;
|
||||||
cropTypes[9].Season[0] = "Spring";
|
|
||||||
cropTypes[9].Season[1] = "Autumn";
|
|
||||||
cropTypes[9].Season[2] = "Whole Year";
|
|
||||||
cropTypes[9].Season[3] = "Winter";
|
|
||||||
cropTypes[9].AreaMin = 1;
|
|
||||||
cropTypes[9].AreaMax = 23000;
|
|
||||||
|
|
||||||
|
|
||||||
//Tobacco
|
//Tobacco
|
||||||
@ -204,18 +146,12 @@ class CropTypesHolder
|
|||||||
cropTypes[10].soilType[0] = "Red";
|
cropTypes[10].soilType[0] = "Red";
|
||||||
cropTypes[10].soilType[1] = null;
|
cropTypes[10].soilType[1] = null;
|
||||||
cropTypes[10].soilType[2] = null;
|
cropTypes[10].soilType[2] = null;
|
||||||
cropTypes[10].CropName = "Tobacco";
|
|
||||||
cropTypes[10].Temparature = 31.9f;
|
cropTypes[10].Temparature = 31.9f;
|
||||||
cropTypes[10].Humidity = 62.4f;
|
cropTypes[10].Humidity = 62.4f;
|
||||||
cropTypes[10].Moisture = 31.6f;
|
cropTypes[10].Moisture = 31.6f;
|
||||||
cropTypes[10].Nitrogen = 21 + 19.1f;
|
cropTypes[10].Nitrogen = 19.1f;
|
||||||
cropTypes[10].Potassium = 10 + 4.9f;
|
cropTypes[10].Potassium = 4.9f;
|
||||||
cropTypes[10].Phosphorous = 20 + 19.3f;
|
cropTypes[10].Phosphorous = 19.3f;
|
||||||
cropTypes[10].Season[0] = "Spring";
|
|
||||||
cropTypes[10].Season[1] = "Autumn";
|
|
||||||
cropTypes[10].Season[2] = "Whole Year";
|
|
||||||
cropTypes[10].AreaMin = 1;
|
|
||||||
cropTypes[10].AreaMax = 9500;
|
|
||||||
|
|
||||||
|
|
||||||
//Wheat
|
//Wheat
|
||||||
@ -223,19 +159,12 @@ class CropTypesHolder
|
|||||||
cropTypes[11].soilType[0] = "Loamy";
|
cropTypes[11].soilType[0] = "Loamy";
|
||||||
cropTypes[11].soilType[1] = null;
|
cropTypes[11].soilType[1] = null;
|
||||||
cropTypes[11].soilType[2] = null;
|
cropTypes[11].soilType[2] = null;
|
||||||
cropTypes[11].CropName = "Wheat";
|
|
||||||
cropTypes[11].Temparature = 33.1f;
|
cropTypes[11].Temparature = 33.1f;
|
||||||
cropTypes[11].Humidity = 63.8f;
|
cropTypes[11].Humidity = 63.8f;
|
||||||
cropTypes[11].Moisture = 50.0f;
|
cropTypes[11].Moisture = 50.0f;
|
||||||
cropTypes[11].Nitrogen = 21 + 23.3f;
|
cropTypes[11].Nitrogen = 23.3f;
|
||||||
cropTypes[11].Potassium = 10 + 2.9f;
|
cropTypes[11].Potassium = 2.9f;
|
||||||
cropTypes[11].Phosphorous = 20 + 14.4f;
|
cropTypes[11].Phosphorous = 14.4f;
|
||||||
cropTypes[11].Season[0] = "Spring";
|
|
||||||
cropTypes[11].Season[1] = "Autumn";
|
|
||||||
cropTypes[11].Season[2] = "Whole Year";
|
|
||||||
cropTypes[11].Season[3] = "Summer";
|
|
||||||
cropTypes[11].AreaMin = 1;
|
|
||||||
cropTypes[11].AreaMax = 266000;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,23 +14,18 @@ class Crops
|
|||||||
private int cropType = 0;
|
private int cropType = 0;
|
||||||
private float Timer = 1;
|
private float Timer = 1;
|
||||||
private int UpdateCrop;
|
private int UpdateCrop;
|
||||||
private float fullTimer = 1;
|
private float fullTimer;
|
||||||
private bool housePos = false;
|
private bool housePos = false;
|
||||||
private Vector2 Size;
|
private Vector2 Size;
|
||||||
private Random r = new Random();
|
|
||||||
private CropTypes DataSet;
|
private CropTypes DataSet;
|
||||||
SoilProperties soilProperties = new SoilProperties();
|
SoilProperties soilProperties = new SoilProperties();
|
||||||
private float ProductionRate;
|
private float ProductionRate;
|
||||||
private float tempRain;
|
|
||||||
private float prevpred;
|
|
||||||
private DayNightCycle Time = new DayNightCycle();
|
|
||||||
private int previousDay = 0;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public void updateCrop(Vector2 newSize, DayNightCycle nTime)
|
public void updateCrop(Vector2 newSize)
|
||||||
{
|
{
|
||||||
Time = nTime;
|
getProductionRate(DataSet);
|
||||||
if (UpdateCrop == 60)
|
if (UpdateCrop == 60)
|
||||||
{
|
{
|
||||||
degradeSoil();
|
degradeSoil();
|
||||||
@ -50,56 +45,11 @@ class Crops
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateProductionRate()
|
|
||||||
{
|
|
||||||
getProductionRate(DataSet);
|
|
||||||
}
|
|
||||||
|
|
||||||
public float getSpeedFactor(float tractorSpeed)
|
|
||||||
{
|
|
||||||
if (getCostOnMovement() == 1)
|
|
||||||
return (1f * tractorSpeed);
|
|
||||||
return (1f * tractorSpeed) / (getCostOnMovement() / 5.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
public SoilProperties getSoilProperties()
|
public SoilProperties getSoilProperties()
|
||||||
{
|
{
|
||||||
return soilProperties;
|
return soilProperties;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Fertilize(Fertilizer fertilizer)
|
|
||||||
{
|
|
||||||
soilProperties.Nitrogen += fertilizer.Nitrogen;
|
|
||||||
soilProperties.Phosphorous += fertilizer.Phosphorus;
|
|
||||||
soilProperties.Potassium += fertilizer.Potassium;
|
|
||||||
|
|
||||||
if (soilProperties.Nitrogen > 42)
|
|
||||||
soilProperties.Nitrogen = 42;
|
|
||||||
if (soilProperties.Phosphorous > 42)
|
|
||||||
soilProperties.Phosphorous = 42;
|
|
||||||
if (soilProperties.Potassium > 19)
|
|
||||||
soilProperties.Potassium = 19;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool isSaturated()
|
|
||||||
{
|
|
||||||
if (soilProperties.Nitrogen > 40 && (soilProperties.Phosphorous > 40 || soilProperties.Potassium > 17))
|
|
||||||
return true;
|
|
||||||
if (soilProperties.Phosphorous > 40 && soilProperties.Potassium > 17)
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool isSaturated(int threshold)
|
|
||||||
{
|
|
||||||
if (soilProperties.Nitrogen > 40 - threshold && (soilProperties.Phosphorous > 40 - threshold || soilProperties.Potassium > 17 - (threshold * 17/40)))
|
|
||||||
return true;
|
|
||||||
if (soilProperties.Phosphorous > 40 - threshold && soilProperties.Potassium > 17 - (threshold *17/40))
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float getCropTimer()
|
public float getCropTimer()
|
||||||
{
|
{
|
||||||
return Timer;
|
return Timer;
|
||||||
@ -120,7 +70,7 @@ class Crops
|
|||||||
// Changes the time required for the crops to be harvestable
|
// Changes the time required for the crops to be harvestable
|
||||||
public void setCropTimer()
|
public void setCropTimer()
|
||||||
{
|
{
|
||||||
if (cropType == 1) // Barley
|
if (cropType == 0) // Carrots
|
||||||
{
|
{
|
||||||
Timer = 300;
|
Timer = 300;
|
||||||
fullTimer = Timer;
|
fullTimer = Timer;
|
||||||
@ -156,108 +106,46 @@ class Crops
|
|||||||
{
|
{
|
||||||
if (cropType == 0)
|
if (cropType == 0)
|
||||||
{
|
{
|
||||||
return 16; //Barley
|
return 15; //Carrots
|
||||||
}
|
}
|
||||||
if (cropType == 1)
|
else if (cropType == 1)
|
||||||
{
|
{
|
||||||
return 16; //Barley
|
return 30; //Wheat
|
||||||
}
|
}
|
||||||
else if (cropType == 2)
|
else if (cropType == 2)
|
||||||
{
|
{
|
||||||
return 16; //Cotton
|
return 40; //Berries
|
||||||
}
|
|
||||||
else if (cropType == 3)
|
|
||||||
{
|
|
||||||
return 16; //Ground Nuts
|
|
||||||
}
|
|
||||||
else if (cropType == 4)
|
|
||||||
{
|
|
||||||
return 16; //Maize
|
|
||||||
}
|
|
||||||
else if (cropType == 5)
|
|
||||||
{
|
|
||||||
return 16; //Millets
|
|
||||||
}
|
|
||||||
else if (cropType == 6)
|
|
||||||
{
|
|
||||||
return 16; //Oil Seeds
|
|
||||||
}
|
|
||||||
else if (cropType == 7)
|
|
||||||
{
|
|
||||||
return 16; //Paddy
|
|
||||||
}
|
|
||||||
else if (cropType == 8)
|
|
||||||
{
|
|
||||||
return 16; //Pulses
|
|
||||||
}
|
|
||||||
else if (cropType == 9)
|
|
||||||
{
|
|
||||||
return 16; //Sugarcane
|
|
||||||
}
|
|
||||||
else if (cropType == 10)
|
|
||||||
{
|
|
||||||
return 16; //Wheat
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return 16; //Tobacco
|
return 50; //Fruit Trees
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void degradeSoil()
|
public void degradeSoil()
|
||||||
{
|
{
|
||||||
Random r = new Random();
|
|
||||||
if (soilProperties.Nitrogen > 4.0f)
|
if (soilProperties.Nitrogen > 4.0f)
|
||||||
{
|
{
|
||||||
soilProperties.Nitrogen = soilProperties.Nitrogen - ((soilProperties.NitrogenDegradeRate * (float)Math.Pow(ProductionRate, 2)) * (float)Math.Pow((r.NextDouble() + 0.5f), 2));
|
soilProperties.Nitrogen = soilProperties.Nitrogen - soilProperties.NitrogenDegradeRate;
|
||||||
}
|
}
|
||||||
if (soilProperties.Phosphorous > 0.1f)
|
if (soilProperties.Phosphorous > 0.1f)
|
||||||
{
|
{
|
||||||
soilProperties.Phosphorous = soilProperties.Phosphorous - ((soilProperties.PhosphorousDegradeRate * (float)Math.Pow(ProductionRate, 2)) * (float)Math.Pow((r.NextDouble() + 0.5f), 2));
|
soilProperties.Phosphorous = soilProperties.Phosphorous - soilProperties.PhosphorousDegradeRate;
|
||||||
}
|
}
|
||||||
if (soilProperties.Potassium > 0.1f)
|
if (soilProperties.Potassium > 0.1f)
|
||||||
{
|
{
|
||||||
soilProperties.Potassium = soilProperties.Potassium - ((soilProperties.PotassiumDegradeRate * (float)Math.Pow(ProductionRate, 2)) * (float)Math.Pow((r.NextDouble() + 0.5f), 2));
|
soilProperties.Potassium = soilProperties.Potassium - soilProperties.PotassiumDegradeRate;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public void updateRainfall(float Rain)
|
|
||||||
{
|
|
||||||
if (Rain >= 0.45f)
|
|
||||||
{
|
|
||||||
soilProperties.Rainfall = soilProperties.Rainfall + Rain * 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPrevRainfall()
|
|
||||||
{
|
|
||||||
|
|
||||||
soilProperties.prevRainfall = soilProperties.Rainfall;
|
|
||||||
if (soilProperties.prevRainfall > 3616)
|
|
||||||
soilProperties.prevRainfall = 3616;
|
|
||||||
else if (soilProperties.prevRainfall < 236)
|
|
||||||
soilProperties.prevRainfall = 236;
|
|
||||||
soilProperties.Rainfall = 0;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void setCropType(int Type, CropTypes nCropType)
|
public void setCropType(int Type, CropTypes nCropType)
|
||||||
{
|
{
|
||||||
if (Timer == fullTimer)
|
DataSet = nCropType;
|
||||||
{
|
cropType = Type;
|
||||||
CropTypes temp = DataSet;
|
|
||||||
DataSet = nCropType;
|
|
||||||
cropType = Type;
|
|
||||||
if (Status > 1)
|
|
||||||
{
|
|
||||||
soilProperties.Area = r.Next(nCropType.AreaMin, nCropType.AreaMax);
|
|
||||||
if (temp != nCropType)
|
|
||||||
updateMLModel(DataSet, 1.0f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getStatus()
|
public int getStatus()
|
||||||
@ -280,7 +168,6 @@ class Crops
|
|||||||
public void setStatus(int newStatus)
|
public void setStatus(int newStatus)
|
||||||
{
|
{
|
||||||
Status = newStatus;
|
Status = newStatus;
|
||||||
Timer = getCropTimer();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setOriginalStatus()
|
public void setOriginalStatus()
|
||||||
@ -294,7 +181,6 @@ class Crops
|
|||||||
housePos = state;
|
housePos = state;
|
||||||
if (state)
|
if (state)
|
||||||
{
|
{
|
||||||
Timer = 1;
|
|
||||||
Status = 1;
|
Status = 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -308,110 +194,23 @@ class Crops
|
|||||||
return housePos;
|
return housePos;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool belowCapacity()
|
|
||||||
{
|
|
||||||
return ((int)(soilProperties.Nitrogen + soilProperties.Potassium + soilProperties.Phosphorous)) < soilProperties.Capacity;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vector4 getColour()
|
|
||||||
{
|
|
||||||
float r, g, b, a;
|
|
||||||
float productionRate, overhead;
|
|
||||||
|
|
||||||
if (ProductionRate > 1.0f)
|
|
||||||
{
|
|
||||||
productionRate = 1.0f;
|
|
||||||
overhead = ProductionRate - 1.0f;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
productionRate = ProductionRate;
|
|
||||||
overhead = 0.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = (1.0f - productionRate) * 4;
|
|
||||||
g = 0.0f + productionRate;
|
|
||||||
b = 0.0f + overhead * 3;
|
|
||||||
a = 255;
|
|
||||||
|
|
||||||
return new Vector4(r, g, b, a);
|
|
||||||
}
|
|
||||||
|
|
||||||
public float getProductionRate(CropTypes Sample)
|
public float getProductionRate(CropTypes Sample)
|
||||||
{
|
{
|
||||||
float predProd = 1.0f;
|
|
||||||
if (Status > 1 && Time.getDays() != previousDay)
|
|
||||||
{
|
|
||||||
predProd = updateMLModel(Sample, predProd);
|
|
||||||
}
|
|
||||||
prevpred = predProd;
|
|
||||||
ProductionRate = 1;
|
ProductionRate = 1;
|
||||||
float min = 1.0f;
|
|
||||||
if (DataSet != null)
|
if (DataSet != null)
|
||||||
{
|
{
|
||||||
//ProductionRate = ProductionRate + (ProductionRate * compareToDatset(soilProperties.Temperature, Sample.Temparature));
|
ProductionRate = ProductionRate + (ProductionRate * compareToDatset(soilProperties.Temperature, Sample.Temparature));
|
||||||
//ProductionRate = ProductionRate + (ProductionRate * compareToDatset(soilProperties.Moisture, Sample.Moisture));
|
ProductionRate = ProductionRate + (ProductionRate * compareToDatset(soilProperties.Moisture, Sample.Moisture));
|
||||||
//ProductionRate = ProductionRate + (ProductionRate * compareToDatset(soilProperties.Humidity, Sample.Humidity));
|
ProductionRate = ProductionRate + (ProductionRate * compareToDatset(soilProperties.Humidity, Sample.Humidity));
|
||||||
if (DataSet.soilType[0] != null)
|
ProductionRate = ProductionRate + (ProductionRate * compareToDatset(soilProperties.Phosphorous, Sample.Phosphorous));
|
||||||
{
|
ProductionRate = ProductionRate + (ProductionRate * compareToDatset(soilProperties.Potassium, Sample.Potassium));
|
||||||
if (Sample.soilType[0] == soilProperties.soilType)
|
ProductionRate = ProductionRate + (ProductionRate * compareToDatset(soilProperties.Nitrogen, Sample.Nitrogen));
|
||||||
{
|
|
||||||
ProductionRate = ProductionRate + 0.1f;
|
|
||||||
}
|
|
||||||
if (DataSet.soilType[1] != null)
|
|
||||||
{
|
|
||||||
if (Sample.soilType[1] == soilProperties.soilType)
|
|
||||||
{
|
|
||||||
ProductionRate = ProductionRate + 0.08f;
|
|
||||||
}
|
|
||||||
if (DataSet.soilType[2] != null)
|
|
||||||
{
|
|
||||||
if (Sample.soilType[2] == soilProperties.soilType)
|
|
||||||
{
|
|
||||||
ProductionRate = ProductionRate + 0.5f;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
min = Math.Min(compareToDatset(soilProperties.Phosphorous, Sample.Phosphorous), Math.Min(compareToDatset(soilProperties.Potassium, Sample.Potassium), compareToDatset(soilProperties.Nitrogen, Sample.Nitrogen)));
|
|
||||||
ProductionRate = ProductionRate + (ProductionRate * min);
|
|
||||||
if (ProductionRate < 0)
|
if (ProductionRate < 0)
|
||||||
{
|
{
|
||||||
ProductionRate = 0;
|
ProductionRate = 0;
|
||||||
}
|
}
|
||||||
ProductionRate = ProductionRate / 1.5f;
|
ProductionRate = ProductionRate / 20;
|
||||||
}
|
}
|
||||||
ProductionRate = (float)Math.Pow(ProductionRate, 2.5f);
|
|
||||||
return ProductionRate * prevpred;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float updateMLModel(CropTypes Sample, float predProd)
|
|
||||||
{
|
|
||||||
previousDay = Time.getDays();
|
|
||||||
bool correctSeason = false;
|
|
||||||
foreach (string i in Sample.Season)
|
|
||||||
{
|
|
||||||
if (i == Time.getTimeOfYear() || i == "Whole Year")
|
|
||||||
{
|
|
||||||
correctSeason = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (correctSeason)
|
|
||||||
{
|
|
||||||
predProd = Game1.Sources.ML_Joel.Engine.PredictProductionwithRainfall(soilProperties, Time);
|
|
||||||
predProd = (predProd / soilProperties.Area) / 2;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
predProd = 0.20f;
|
|
||||||
|
|
||||||
return predProd;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float getProductionRate()
|
|
||||||
{
|
|
||||||
return ProductionRate;
|
return ProductionRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -435,26 +234,26 @@ class Crops
|
|||||||
spriteBatch.Begin();
|
spriteBatch.Begin();
|
||||||
if (housePos)
|
if (housePos)
|
||||||
{
|
{
|
||||||
spriteBatch.DrawString(Bold, "Tiletype: House", new Vector2(240, Size.Y * (tileSize + Spacing) + 42), Color.Teal);
|
spriteBatch.DrawString(Bold, "Tiletype: House", new Vector2(240, Size.Y * (tileSize + Spacing) + 42), Color.DarkBlue);
|
||||||
}
|
}
|
||||||
else if (Status == 0)
|
else if (Status == 0)
|
||||||
{
|
{
|
||||||
spriteBatch.DrawString(Bold, "Tiletype: Boulders", new Vector2(240, Size.Y * (tileSize + Spacing) + 42), Color.Teal);
|
spriteBatch.DrawString(Bold, "Tiletype: Boulders", new Vector2(240, Size.Y * (tileSize + Spacing) + 42), Color.DarkBlue);
|
||||||
}
|
}
|
||||||
else if (Status == 1)
|
else if (Status == 1)
|
||||||
{
|
{
|
||||||
spriteBatch.DrawString(Bold, "Tiletype: Grassfield", new Vector2(240, Size.Y * (tileSize + Spacing) + 42), Color.Teal);
|
spriteBatch.DrawString(Bold, "Tiletype: Grassfield", new Vector2(240, Size.Y * (tileSize + Spacing) + 42), Color.DarkBlue);
|
||||||
}
|
}
|
||||||
else if (Status == 2)
|
else if (Status == 2)
|
||||||
{
|
{
|
||||||
spriteBatch.DrawString(Bold, "Tiletype: Soil", new Vector2(240, Size.Y * (tileSize + Spacing) + 42), Color.Teal);
|
spriteBatch.DrawString(Bold, "Tiletype: Soil", new Vector2(240, Size.Y * (tileSize + Spacing) + 42), Color.DarkBlue);
|
||||||
}
|
}
|
||||||
else if (Status == 3)
|
else if (Status == 3)
|
||||||
{
|
{
|
||||||
int x = (int)(((float)Timer / fullTimer) * 100);
|
int x = (int)(((float)Timer / fullTimer) * 100);
|
||||||
x = 100 - x;
|
x = 100 - x;
|
||||||
spriteBatch.DrawString(Bold, "Tiletype: Crop ", new Vector2(240, Size.Y * (tileSize + Spacing) + 42), Color.Teal);
|
spriteBatch.DrawString(Bold, "Tiletype: Crop ", new Vector2(240, Size.Y * (tileSize + Spacing) + 42), Color.DarkBlue);
|
||||||
spriteBatch.DrawString(Bold, "Completion: " + x + "%", new Vector2(240, Size.Y * (tileSize + Spacing) + 82), Color.Teal);
|
spriteBatch.DrawString(Bold, "Completion: " + x + "%", new Vector2(240, Size.Y * (tileSize + Spacing) + 82), Color.DarkBlue);
|
||||||
}
|
}
|
||||||
if (Status != 3)
|
if (Status != 3)
|
||||||
{
|
{
|
||||||
@ -462,37 +261,29 @@ class Crops
|
|||||||
}
|
}
|
||||||
if (Status > 1)
|
if (Status > 1)
|
||||||
{
|
{
|
||||||
spriteBatch.DrawString(Bold, "Prefered Crop: " + cropTypesNames[cropType], new Vector2(240, Size.Y * (tileSize + Spacing) + 62), Color.Teal);
|
spriteBatch.DrawString(Bold, "Prefered Crop: " + cropTypesNames[cropType], new Vector2(240, Size.Y * (tileSize + Spacing) + 62), Color.DarkBlue);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
spriteBatch.DrawString(Bold, "None", new Vector2(240, Size.Y * (tileSize + Spacing) + 62), Color.Teal);
|
spriteBatch.DrawString(Bold, "None", new Vector2(240, Size.Y * (tileSize + Spacing) + 62), Color.DarkBlue);
|
||||||
}
|
}
|
||||||
spriteBatch.DrawString(Bold, "Soil Properties:", new Vector2(240, Size.Y * (tileSize + Spacing) + 122), Color.DarkRed);
|
spriteBatch.DrawString(Bold, "Soil Properties:", new Vector2(240, Size.Y * (tileSize + Spacing) + 122), Color.DarkRed);
|
||||||
spriteBatch.DrawString(Bold, "Soil Type: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 142), Color.DarkRed);
|
spriteBatch.DrawString(Bold, "Soil Type: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 142), Color.DarkRed);
|
||||||
spriteBatch.DrawString(Bold, soilProperties.soilType, new Vector2(370, Size.Y * (tileSize + Spacing) + 142), Color.Teal);
|
spriteBatch.DrawString(Bold, soilProperties.soilType, new Vector2(370, Size.Y * (tileSize + Spacing) + 142), Color.DarkBlue);
|
||||||
spriteBatch.DrawString(Bold, "Temparature: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 162), Color.DarkRed);
|
spriteBatch.DrawString(Bold, "Temparature: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 162), Color.DarkRed);
|
||||||
spriteBatch.DrawString(Bold, soilProperties.Temperature.ToString(), new Vector2(370, Size.Y * (tileSize + Spacing) + 162), Color.Teal);
|
spriteBatch.DrawString(Bold, soilProperties.Temperature.ToString(), new Vector2(370, Size.Y * (tileSize + Spacing) + 162), Color.DarkBlue);
|
||||||
spriteBatch.DrawString(Bold, "Moisture: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 182), Color.DarkRed);
|
spriteBatch.DrawString(Bold, "Moisture: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 182), Color.DarkRed);
|
||||||
spriteBatch.DrawString(Bold, soilProperties.Moisture.ToString(), new Vector2(370, Size.Y * (tileSize + Spacing) + 182), Color.Teal);
|
spriteBatch.DrawString(Bold, soilProperties.Moisture.ToString(), new Vector2(370, Size.Y * (tileSize + Spacing) + 182), Color.DarkBlue);
|
||||||
spriteBatch.DrawString(Bold, "Humidity: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 202), Color.DarkRed);
|
spriteBatch.DrawString(Bold, "Humidity: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 202), Color.DarkRed);
|
||||||
spriteBatch.DrawString(Bold, soilProperties.Humidity.ToString(), new Vector2(370, Size.Y * (tileSize + Spacing) + 202), Color.Teal);
|
spriteBatch.DrawString(Bold, soilProperties.Humidity.ToString(), new Vector2(370, Size.Y * (tileSize + Spacing) + 202), Color.DarkBlue);
|
||||||
spriteBatch.DrawString(Bold, "Phosphorous: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 222), Color.DarkRed);
|
spriteBatch.DrawString(Bold, "Phosphorous: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 222), Color.DarkRed);
|
||||||
spriteBatch.DrawString(Bold, Math.Round(soilProperties.Phosphorous,1).ToString(), new Vector2(370, Size.Y * (tileSize + Spacing) + 222), Color.Teal);
|
spriteBatch.DrawString(Bold, Math.Round(soilProperties.Phosphorous,1).ToString(), new Vector2(370, Size.Y * (tileSize + Spacing) + 222), Color.DarkBlue);
|
||||||
spriteBatch.DrawString(Bold, "Potassium: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 242), Color.DarkRed);
|
spriteBatch.DrawString(Bold, "Potassium: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 242), Color.DarkRed);
|
||||||
spriteBatch.DrawString(Bold, Math.Round(soilProperties.Potassium, 1).ToString(), new Vector2(370, Size.Y * (tileSize + Spacing) + 242), Color.Teal);
|
spriteBatch.DrawString(Bold, Math.Round(soilProperties.Potassium, 1).ToString(), new Vector2(370, Size.Y * (tileSize + Spacing) + 242), Color.DarkBlue);
|
||||||
spriteBatch.DrawString(Bold, "Nitrogen: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 262), Color.DarkRed);
|
spriteBatch.DrawString(Bold, "Nitrogen: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 262), Color.DarkRed);
|
||||||
spriteBatch.DrawString(Bold, Math.Round(soilProperties.Nitrogen, 1).ToString(), new Vector2(370, Size.Y * (tileSize + Spacing) + 262), Color.Teal);
|
spriteBatch.DrawString(Bold, Math.Round(soilProperties.Nitrogen, 1).ToString(), new Vector2(370, Size.Y * (tileSize + Spacing) + 262), Color.DarkBlue);
|
||||||
spriteBatch.DrawString(Bold, "Production Rate: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 282), Color.DarkRed);
|
spriteBatch.DrawString(Bold, "Production Rate: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 282), Color.DarkRed);
|
||||||
spriteBatch.DrawString(Bold, Math.Round((ProductionRate * 100), 1).ToString() + "%", new Vector2(370, Size.Y * (tileSize + Spacing) + 282), Color.Teal);
|
spriteBatch.DrawString(Bold, Math.Round((ProductionRate * 100), 1).ToString() + "%", new Vector2(370, Size.Y * (tileSize + Spacing) + 282), Color.DarkBlue);
|
||||||
spriteBatch.DrawString(Bold, "Last Years Rainfall: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 302), Color.DarkRed);
|
|
||||||
spriteBatch.DrawString(Bold, Math.Round((soilProperties.prevRainfall), 1).ToString() + "mm", new Vector2(370, Size.Y * (tileSize + Spacing) + 302), Color.Teal);
|
|
||||||
spriteBatch.DrawString(Bold, "Rainfall: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 322), Color.DarkRed);
|
|
||||||
spriteBatch.DrawString(Bold, Math.Round((soilProperties.Rainfall), 1).ToString() + "mm", new Vector2(370, Size.Y * (tileSize + Spacing) + 322), Color.Teal);
|
|
||||||
spriteBatch.DrawString(Bold, "Rain mm/s: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 342), Color.DarkRed);
|
|
||||||
spriteBatch.DrawString(Bold, Math.Round((tempRain * 2), 2).ToString() + "mm", new Vector2(370, Size.Y * (tileSize + Spacing) + 342), Color.Teal);
|
|
||||||
spriteBatch.DrawString(Bold, "Area: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 362), Color.DarkRed);
|
|
||||||
spriteBatch.DrawString(Bold, soilProperties.Area + "m^2", new Vector2(370, Size.Y * (tileSize + Spacing) + 362), Color.Teal);
|
|
||||||
spriteBatch.End();
|
spriteBatch.End();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@ -14,116 +12,35 @@ class Farm
|
|||||||
private Random r;
|
private Random r;
|
||||||
private CropTypesHolder PresetCrops = new CropTypesHolder();
|
private CropTypesHolder PresetCrops = new CropTypesHolder();
|
||||||
private int Update;
|
private int Update;
|
||||||
private Astar astar = new Astar();
|
|
||||||
private PerlinNoise perlin = new PerlinNoise();
|
|
||||||
private Vector2 RainPosition;
|
|
||||||
private Vector2 WindSpeed = new Vector2(0,0);
|
|
||||||
private System.Drawing.Color[][] RainfallMap;
|
|
||||||
private float[][] whiteNoise;
|
|
||||||
private float[][] perlinNoise;
|
|
||||||
private DayNightCycle Time;
|
|
||||||
private float updatePerc = 0.01f;
|
|
||||||
private float updateProgress = 0;
|
|
||||||
private float nextUpdate = 0;
|
|
||||||
private int productionUpdate = 0;
|
|
||||||
private string path_base = FindPath();
|
|
||||||
|
|
||||||
|
|
||||||
//initializes the crops
|
//initializes the crops
|
||||||
public void init(Vector2 Size, Vector2 housepos)
|
public void init(Vector2 Size, Vector2 housepos)
|
||||||
{
|
{
|
||||||
whiteNoise = PerlinNoise.GenerateWhiteNoise(100, 100);
|
|
||||||
perlinNoise = PerlinNoise.GeneratePerlinNoise(whiteNoise, 1);
|
|
||||||
PresetCrops.init();
|
PresetCrops.init();
|
||||||
r = new Random();
|
r = new Random();
|
||||||
crops = new Crops[100, 100];
|
crops = new Crops[100, 100];
|
||||||
int dirtCount = 0;
|
|
||||||
for (int i = 0; i < 99; i++)
|
for (int i = 0; i < 99; i++)
|
||||||
{
|
{
|
||||||
for (int j = 0; j < 99; j++)
|
for (int j = 0; j < 99; j++)
|
||||||
{
|
{
|
||||||
int x = 0;
|
int x = r.Next(0, 3);
|
||||||
|
if (x == 0)
|
||||||
if (perlinNoise[i][j] > 0 && perlinNoise[i][j] < 0.15f)
|
{
|
||||||
x = 0;
|
x = r.Next(0, 2);
|
||||||
else if (perlinNoise[i][j] >= 0.15f && perlinNoise[i][j] < 0.8f)
|
}
|
||||||
x = 1;
|
if (x == 2)
|
||||||
else if (perlinNoise[i][j] >= 0.8f)
|
{
|
||||||
x = 2;
|
x = r.Next(1, 3);
|
||||||
|
}
|
||||||
crops[i, j] = new Crops();
|
crops[i, j] = new Crops();
|
||||||
crops[i, j].setStatus(x);
|
crops[i, j].setStatus(x);
|
||||||
crops[i, j].setOriginalStatus();
|
crops[i, j].setOriginalStatus();
|
||||||
x = r.Next(1, 12);
|
x = r.Next(0, 12);
|
||||||
crops[i, j].setCropType(x, PresetCrops.getPresetCropTypes(x));
|
crops[i, j].setCropType(x, PresetCrops.getPresetCropTypes(x));
|
||||||
crops[i, j].init();
|
crops[i, j].init();
|
||||||
|
|
||||||
if (crops[i, j].getStatus() == 2)
|
|
||||||
{
|
|
||||||
dirtCount++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int i = 0; i < 99; i++)
|
|
||||||
{
|
|
||||||
for (int j = 0; j < 99; j++)
|
|
||||||
{
|
|
||||||
if (crops[i, j].getStatus() == 2)
|
|
||||||
{
|
|
||||||
if (!astar.isReachable(crops, new Vector2((int)i, (int)j), housepos))
|
|
||||||
{
|
|
||||||
dirtCount--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (dirtCount != 0)
|
|
||||||
init(Size, housepos);
|
|
||||||
RainPosition.X = r.Next(0, 1900);
|
|
||||||
RainPosition.Y = r.Next(0, 1950);
|
|
||||||
float coef = GetRandomNumber(-1f, 1f);
|
|
||||||
if (coef < 0)
|
|
||||||
coef = -1.0f;
|
|
||||||
else
|
|
||||||
coef = 1.0f;
|
|
||||||
WindSpeed.X = GetRandomNumber(0.9f, 1f) / 50 * coef;
|
|
||||||
WindSpeed.Y = GetRandomNumber(0.9f, 1f) / 50 * coef;
|
|
||||||
RainfallMap = PerlinNoise.LoadImage(System.IO.Path.Combine(path_base, "Content/Rainfall.png"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public Rectangle getRainPosition(int TileSize, int x, int y, Vector2 Size)
|
|
||||||
{
|
|
||||||
float xtrunc = RainPosition.X - (float)Math.Truncate(RainPosition.X);
|
|
||||||
float ytrunc = RainPosition.Y - (float)Math.Truncate(RainPosition.Y);
|
|
||||||
|
|
||||||
if (xtrunc > 0.5)
|
|
||||||
xtrunc = xtrunc - 1;
|
|
||||||
|
|
||||||
if (ytrunc > 0.5)
|
|
||||||
ytrunc = ytrunc - 1;
|
|
||||||
xtrunc = -xtrunc;
|
|
||||||
ytrunc = -ytrunc;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//return new Rectangle((int)(xtrunc * TileSize) + x * TileSize,(int)(ytrunc * TileSize) + y * TileSize, TileSize, TileSize);
|
|
||||||
return new Rectangle((int)(xtrunc * TileSize) + x * TileSize, (int)(ytrunc * TileSize) + y * TileSize, TileSize, TileSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Rectangle getDestinationRectangle(int x, int y, Vector2 Size)
|
|
||||||
{
|
|
||||||
Vector2 temp = new Vector2((int)Math.Round(x + RainPosition.X), y + (int)Math.Round(RainPosition.Y));
|
|
||||||
if (temp.X >= 1999 - Size.X - 1)
|
|
||||||
temp.X = -(1999 - (int)Math.Round(RainPosition.X));
|
|
||||||
if (temp.Y >= 1999 - Size.Y - 1)
|
|
||||||
temp.Y = -(1999 - (int)Math.Round(RainPosition.Y));
|
|
||||||
return new Rectangle((int)temp.X, (int)temp.Y, 1, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void drawWeatherInformation(SpriteBatch spriteBatch, SpriteFont Bold, Input input)
|
|
||||||
{
|
|
||||||
spriteBatch.DrawString(Bold, "WindSpeed: " + Math.Round(WindSpeed.X, 4), new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 282), Color.Teal);
|
|
||||||
spriteBatch.DrawString(Bold, " : ", new Vector2(153, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 282), Color.Teal);
|
|
||||||
spriteBatch.DrawString(Bold, Math.Round(WindSpeed.Y, 4).ToString(), new Vector2(163, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 282), Color.Teal);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateFarm(Vector2 Size)
|
public void updateFarm(Vector2 Size)
|
||||||
@ -135,58 +52,13 @@ class Farm
|
|||||||
{
|
{
|
||||||
for (int j = 0; j < Size.Y; j++)
|
for (int j = 0; j < Size.Y; j++)
|
||||||
{
|
{
|
||||||
Vector2 temp = new Vector2((int)Math.Round(i + RainPosition.X), j + (int)Math.Round(RainPosition.Y));
|
|
||||||
if (temp.X >= 1999 - Size.X - 1)
|
crops[i, j].updateCrop(Size);
|
||||||
temp.X = i + ((1999 - (int)Math.Round(RainPosition.X)));
|
|
||||||
if (temp.Y >= 1999 - Size.Y - 1)
|
|
||||||
temp.Y = i + ((1999 - (int)Math.Round(RainPosition.Y)));
|
|
||||||
crops[i, j].updateCrop(Size, Time);
|
|
||||||
crops[i, j].updateRainfall(RainfallMap[(int)Math.Round(temp.X)][(int)Math.Round(temp.Y)].GetBrightness());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Update = 0;
|
Update = 0;
|
||||||
}
|
}
|
||||||
updateRainMapPosition(Size);
|
|
||||||
if (productionUpdate == 2)
|
|
||||||
{
|
|
||||||
nextUpdate = updateProgress + updatePerc;
|
|
||||||
for (int i = (int)(updateProgress * Size.X); i < nextUpdate * Size.X; i++)
|
|
||||||
{
|
|
||||||
for (int j = 0; j < Size.Y; j++)
|
|
||||||
{
|
|
||||||
if (crops[i, j].getStatus() > 1)
|
|
||||||
{
|
|
||||||
int x = getHighestProductionRate(i, j);
|
|
||||||
crops[i, j].setCropType(x, PresetCrops.getPresetCropTypes(x));
|
|
||||||
crops[i, j].updateProductionRate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
updateProgress = updateProgress + updatePerc;
|
|
||||||
if (updateProgress >= 1)
|
|
||||||
{
|
|
||||||
updateProgress = 0;
|
|
||||||
}
|
|
||||||
productionUpdate = 0;
|
|
||||||
nextUpdate = 0;
|
|
||||||
}
|
|
||||||
productionUpdate++;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updateRainFall(Vector2 Size, DayNightCycle nTime)
|
|
||||||
{
|
|
||||||
Time = nTime;
|
|
||||||
if (nTime.nDay())
|
|
||||||
{
|
|
||||||
for (int i = 0; i < Size.X; i++)
|
|
||||||
{
|
|
||||||
for (int j = 0; j < Size.Y; j++)
|
|
||||||
{
|
|
||||||
crops[i, j].setPrevRainfall();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Changes the properties of the tile when the tractor reaches this tile.
|
//Changes the properties of the tile when the tractor reaches this tile.
|
||||||
@ -204,7 +76,6 @@ class Farm
|
|||||||
}
|
}
|
||||||
else if (crops[x, y].getStatus() == 2)
|
else if (crops[x, y].getStatus() == 2)
|
||||||
{
|
{
|
||||||
|
|
||||||
crops[x, y].setStatus(3);
|
crops[x, y].setStatus(3);
|
||||||
crops[x, y].setCropTimer();
|
crops[x, y].setCropTimer();
|
||||||
}
|
}
|
||||||
@ -220,42 +91,6 @@ class Farm
|
|||||||
return crops;
|
return crops;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateRainMapPosition(Vector2 Size)
|
|
||||||
{
|
|
||||||
double x, y;
|
|
||||||
x = WindSpeed.X + GetRandomNumber(-1f, 1f) / 20000;
|
|
||||||
y = WindSpeed.Y + GetRandomNumber(-1f, 1f) / 20000;
|
|
||||||
if (x <= 0.02f && x >= -0.02f)
|
|
||||||
{
|
|
||||||
WindSpeed.X = (float)x;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (y < 0.02f && y > -0.02f)
|
|
||||||
{
|
|
||||||
WindSpeed.Y = (float)y;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (WindSpeed.X > 0 && RainPosition.X < 2000)
|
|
||||||
RainPosition.X = RainPosition.X + WindSpeed.X;
|
|
||||||
else if (WindSpeed.X < 0 && RainPosition.X > 0)
|
|
||||||
RainPosition.X = RainPosition.X + WindSpeed.X;
|
|
||||||
|
|
||||||
if (WindSpeed.Y > 0 && RainPosition.Y < 2000)
|
|
||||||
RainPosition.Y = RainPosition.Y + WindSpeed.Y;
|
|
||||||
else if (WindSpeed.Y < 0 && RainPosition.Y > 0)
|
|
||||||
RainPosition.Y = RainPosition.Y + WindSpeed.Y;
|
|
||||||
|
|
||||||
if (Math.Round(RainPosition.X) == 1999 && WindSpeed.X > 0)
|
|
||||||
RainPosition.X = 0;
|
|
||||||
else if (Math.Round(RainPosition.X) == 1 && WindSpeed.X < 0)
|
|
||||||
RainPosition.X = 1999;
|
|
||||||
|
|
||||||
if (Math.Round(RainPosition.Y) == 1999 && WindSpeed.Y > 0)
|
|
||||||
RainPosition.Y = 0;
|
|
||||||
else if (Math.Round(RainPosition.Y) == 1 && WindSpeed.Y < 0)
|
|
||||||
RainPosition.Y = 1999;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setNewHousePos(Vector2 pos, bool newState)
|
public void setNewHousePos(Vector2 pos, bool newState)
|
||||||
{
|
{
|
||||||
crops[(int)pos.X, (int)pos.Y].setHousePos(newState);
|
crops[(int)pos.X, (int)pos.Y].setHousePos(newState);
|
||||||
@ -263,7 +98,7 @@ class Farm
|
|||||||
|
|
||||||
public CropTypes getPresetCropTypes(int Index)
|
public CropTypes getPresetCropTypes(int Index)
|
||||||
{
|
{
|
||||||
return PresetCrops.getPresetCropTypes(Index);
|
return PresetCrops.getPresetCropTypes(Index - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCropType(int x, int y, int Type)
|
public void setCropType(int x, int y, int Type)
|
||||||
@ -277,18 +112,15 @@ class Farm
|
|||||||
{
|
{
|
||||||
for (int j = 0; j < Size.X; j++)
|
for (int j = 0; j < Size.X; j++)
|
||||||
{
|
{
|
||||||
if (crops[i, j].getStatus() == 2)
|
int x = getHighestProductionRate(i, j);
|
||||||
{
|
crops[i,j].setCropType(x, PresetCrops.getPresetCropTypes(x));
|
||||||
int x = getHighestProductionRate(i, j);
|
|
||||||
crops[i, j].setCropType(x, PresetCrops.getPresetCropTypes(x));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getHighestProductionRate(int x, int y)
|
private int getHighestProductionRate(int x, int y)
|
||||||
{
|
{
|
||||||
int i = 6, holderIndex = 0;
|
int i = 1, holderIndex = 0;
|
||||||
float holder = 0, SampleHolder = 0;
|
float holder = 0, SampleHolder = 0;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
@ -303,47 +135,8 @@ class Farm
|
|||||||
return holderIndex;
|
return holderIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Color getRainAmount(int x, int y, Color color, Vector2 Size)
|
|
||||||
{
|
|
||||||
Vector2 temp = new Vector2(x + (int)Math.Round(RainPosition.X), y + (int)Math.Round(RainPosition.Y));
|
|
||||||
if (temp.X >= 1999)
|
|
||||||
temp.X = -(1999 - (int)Math.Round(temp.X));
|
|
||||||
if (temp.Y >= 1999)
|
|
||||||
temp.Y = -(1999 - (int)Math.Round(temp.Y));
|
|
||||||
if (temp.X == -1)
|
|
||||||
temp.X = 1999;
|
|
||||||
if (temp.Y == -1)
|
|
||||||
temp.Y = 1999;
|
|
||||||
if (RainfallMap[(int)temp.X][(int)temp.Y].GetBrightness() < 0.45f)
|
|
||||||
{
|
|
||||||
return Color.FromNonPremultiplied(color.R, color.G, color.B, (int)(0));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return Color.FromNonPremultiplied(color.R, color.G, color.B, (int)(255 * RainfallMap[(int)temp.X][(int)temp.Y].GetBrightness()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public float getProductionRate(int x, int y, int Type)
|
public float getProductionRate(int x, int y, int Type)
|
||||||
{
|
{
|
||||||
return crops[x, y]. getProductionRate(PresetCrops.getPresetCropTypes(Type));
|
return crops[x, y].getProductionRate(PresetCrops.getPresetCropTypes(Type));
|
||||||
}
|
|
||||||
|
|
||||||
public float GetRandomNumber(double minimum, double maximum)
|
|
||||||
{
|
|
||||||
return (float)(Math.Round(r.NextDouble() * (maximum - minimum) + minimum, 2));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string FindPath()
|
|
||||||
{
|
|
||||||
string path = System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location).ToString();
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
path = Directory.GetParent(path).ToString();
|
|
||||||
if (path.EndsWith("\\Game1"))
|
|
||||||
{
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,333 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Drawing;
|
|
||||||
using System.Drawing.Imaging;
|
|
||||||
|
|
||||||
class PerlinNoise
|
|
||||||
{
|
|
||||||
#region Feilds
|
|
||||||
static Random random = new Random();
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Reusable Functions
|
|
||||||
|
|
||||||
public static float[][] GenerateWhiteNoise(int width, int height)
|
|
||||||
{
|
|
||||||
float[][] noise = GetEmptyArray<float>(width, height);
|
|
||||||
|
|
||||||
for (int i = 0; i < width; i++)
|
|
||||||
{
|
|
||||||
for (int j = 0; j < height; j++)
|
|
||||||
{
|
|
||||||
noise[i][j] = (float)random.NextDouble() % 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return noise;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static float Interpolate(float x0, float x1, float alpha)
|
|
||||||
{
|
|
||||||
return x0 * (1 - alpha) + alpha * x1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Color Interpolate(Color col0, Color col1, float alpha)
|
|
||||||
{
|
|
||||||
float beta = 1 - alpha;
|
|
||||||
return Color.FromArgb(
|
|
||||||
255,
|
|
||||||
(int)(col0.R * alpha + col1.R * beta),
|
|
||||||
(int)(col0.G * alpha + col1.G * beta),
|
|
||||||
(int)(col0.B * alpha + col1.B * beta));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Color GetColor(Color gradientStart, Color gradientEnd, float t)
|
|
||||||
{
|
|
||||||
float u = 1 - t;
|
|
||||||
|
|
||||||
Color color = Color.FromArgb(
|
|
||||||
255,
|
|
||||||
(int)(gradientStart.R * u + gradientEnd.R * t),
|
|
||||||
(int)(gradientStart.G * u + gradientEnd.G * t),
|
|
||||||
(int)(gradientStart.B * u + gradientEnd.B * t));
|
|
||||||
|
|
||||||
return color;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Color[][] MapGradient(Color gradientStart, Color gradientEnd, float[][] perlinNoise)
|
|
||||||
{
|
|
||||||
int width = perlinNoise.Length;
|
|
||||||
int height = perlinNoise[0].Length;
|
|
||||||
|
|
||||||
Color[][] image = GetEmptyArray<Color>(width, height); //an array of colours
|
|
||||||
|
|
||||||
for (int i = 0; i < width; i++)
|
|
||||||
{
|
|
||||||
for (int j = 0; j < height; j++)
|
|
||||||
{
|
|
||||||
image[i][j] = GetColor(gradientStart, gradientEnd, perlinNoise[i][j]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return image;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static T[][] GetEmptyArray<T>(int width, int height)
|
|
||||||
{
|
|
||||||
T[][] image = new T[width][];
|
|
||||||
|
|
||||||
for (int i = 0; i < width; i++)
|
|
||||||
{
|
|
||||||
image[i] = new T[height];
|
|
||||||
}
|
|
||||||
|
|
||||||
return image;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static float[][] GenerateSmoothNoise(float[][] baseNoise, int octave)
|
|
||||||
{
|
|
||||||
int width = baseNoise.Length;
|
|
||||||
int height = baseNoise[0].Length;
|
|
||||||
|
|
||||||
float[][] smoothNoise = GetEmptyArray<float>(width, height);
|
|
||||||
|
|
||||||
int samplePeriod = 1 << octave; // calculates 2 ^ k
|
|
||||||
float sampleFrequency = 1.0f / samplePeriod;
|
|
||||||
|
|
||||||
for (int i = 0; i < width; i++)
|
|
||||||
{
|
|
||||||
//calculate the horizontal sampling indices
|
|
||||||
int sample_i0 = (i / samplePeriod) * samplePeriod;
|
|
||||||
int sample_i1 = (sample_i0 + samplePeriod) % width; //wrap around
|
|
||||||
float horizontal_blend = (i - sample_i0) * sampleFrequency;
|
|
||||||
|
|
||||||
for (int j = 0; j < height; j++)
|
|
||||||
{
|
|
||||||
//calculate the vertical sampling indices
|
|
||||||
int sample_j0 = (j / samplePeriod) * samplePeriod;
|
|
||||||
int sample_j1 = (sample_j0 + samplePeriod) % height; //wrap around
|
|
||||||
float vertical_blend = (j - sample_j0) * sampleFrequency;
|
|
||||||
|
|
||||||
//blend the top two corners
|
|
||||||
float top = Interpolate(baseNoise[sample_i0][sample_j0],
|
|
||||||
baseNoise[sample_i1][sample_j0], horizontal_blend);
|
|
||||||
|
|
||||||
//blend the bottom two corners
|
|
||||||
float bottom = Interpolate(baseNoise[sample_i0][sample_j1],
|
|
||||||
baseNoise[sample_i1][sample_j1], horizontal_blend);
|
|
||||||
|
|
||||||
//final blend
|
|
||||||
smoothNoise[i][j] = Interpolate(top, bottom, vertical_blend);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return smoothNoise;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static float[][] GeneratePerlinNoise(float[][] baseNoise, int octaveCount)
|
|
||||||
{
|
|
||||||
int width = baseNoise.Length;
|
|
||||||
int height = baseNoise[0].Length;
|
|
||||||
|
|
||||||
float[][][] smoothNoise = new float[octaveCount][][]; //an array of 2D arrays containing
|
|
||||||
|
|
||||||
float persistance = 0.7f;
|
|
||||||
|
|
||||||
//generate smooth noise
|
|
||||||
for (int i = 0; i < octaveCount; i++)
|
|
||||||
{
|
|
||||||
smoothNoise[i] = GenerateSmoothNoise(baseNoise, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
float[][] perlinNoise = GetEmptyArray<float>(width, height); //an array of floats initialised to 0
|
|
||||||
|
|
||||||
float amplitude = 1.0f;
|
|
||||||
float totalAmplitude = 0.0f;
|
|
||||||
|
|
||||||
//blend noise together
|
|
||||||
for (int octave = octaveCount - 1; octave >= 0; octave--)
|
|
||||||
{
|
|
||||||
amplitude *= persistance;
|
|
||||||
totalAmplitude += amplitude;
|
|
||||||
|
|
||||||
for (int i = 0; i < width; i++)
|
|
||||||
{
|
|
||||||
for (int j = 0; j < height; j++)
|
|
||||||
{
|
|
||||||
perlinNoise[i][j] += smoothNoise[octave][i][j] * amplitude;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//normalisation
|
|
||||||
for (int i = 0; i < width; i++)
|
|
||||||
{
|
|
||||||
for (int j = 0; j < height; j++)
|
|
||||||
{
|
|
||||||
perlinNoise[i][j] /= totalAmplitude;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return perlinNoise;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static float[][] GeneratePerlinNoise(int width, int height, int octaveCount)
|
|
||||||
{
|
|
||||||
float[][] baseNoise = GenerateWhiteNoise(width, height);
|
|
||||||
|
|
||||||
return GeneratePerlinNoise(baseNoise, octaveCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Color[][] MapToGrey(float[][] greyValues)
|
|
||||||
{
|
|
||||||
int width = greyValues.Length;
|
|
||||||
int height = greyValues[0].Length;
|
|
||||||
|
|
||||||
Color[][] image = GetEmptyArray<Color>(width, height);
|
|
||||||
|
|
||||||
for (int i = 0; i < width; i++)
|
|
||||||
{
|
|
||||||
for (int j = 0; j < height; j++)
|
|
||||||
{
|
|
||||||
int grey = (int)(255 * greyValues[i][j]);
|
|
||||||
Color color = Color.FromArgb(255, grey, grey, grey);
|
|
||||||
|
|
||||||
image[i][j] = color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return image;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SaveImage(Color[][] image, string fileName)
|
|
||||||
{
|
|
||||||
int width = image.Length;
|
|
||||||
int height = image[0].Length;
|
|
||||||
|
|
||||||
Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb);
|
|
||||||
|
|
||||||
for (int i = 0; i < width; i++)
|
|
||||||
{
|
|
||||||
for (int j = 0; j < height; j++)
|
|
||||||
{
|
|
||||||
bitmap.SetPixel(i, j, image[i][j]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bitmap.Save(fileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Color[][] LoadImage(string fileName)
|
|
||||||
{
|
|
||||||
Bitmap bitmap = new Bitmap(fileName);
|
|
||||||
|
|
||||||
int width = bitmap.Width;
|
|
||||||
int height = bitmap.Height;
|
|
||||||
|
|
||||||
Color[][] image = GetEmptyArray<Color>(width, height);
|
|
||||||
|
|
||||||
for (int i = 0; i < width; i++)
|
|
||||||
{
|
|
||||||
for (int j = 0; j < height; j++)
|
|
||||||
{
|
|
||||||
image[i][j] = bitmap.GetPixel(i, j);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return image;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Color[][] BlendImages(Color[][] image1, Color[][] image2, float[][] perlinNoise)
|
|
||||||
{
|
|
||||||
int width = image1.Length;
|
|
||||||
int height = image1[0].Length;
|
|
||||||
|
|
||||||
Color[][] image = GetEmptyArray<Color>(width, height); //an array of colours for the new image
|
|
||||||
|
|
||||||
for (int i = 0; i < width; i++)
|
|
||||||
{
|
|
||||||
for (int j = 0; j < height; j++)
|
|
||||||
{
|
|
||||||
image[i][j] = Interpolate(image1[i][j], image2[i][j], perlinNoise[i][j]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return image;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void DemoGradientMap()
|
|
||||||
{
|
|
||||||
int width = 256;
|
|
||||||
int height = 256;
|
|
||||||
int octaveCount = 8;
|
|
||||||
|
|
||||||
Color gradientStart = Color.FromArgb(255, 0, 0);
|
|
||||||
Color gradientEnd = Color.FromArgb(255, 0, 255);
|
|
||||||
|
|
||||||
float[][] perlinNoise = GeneratePerlinNoise(width, height, octaveCount);
|
|
||||||
Color[][] perlinImage = MapGradient(gradientStart, gradientEnd, perlinNoise);
|
|
||||||
SaveImage(perlinImage, "perlin_noise.png");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static float[][] AdjustLevels(float[][] image, float low, float high)
|
|
||||||
{
|
|
||||||
int width = image.Length;
|
|
||||||
int height = image[0].Length;
|
|
||||||
|
|
||||||
float[][] newImage = GetEmptyArray<float>(width, height);
|
|
||||||
|
|
||||||
for (int i = 0; i < width; i++)
|
|
||||||
{
|
|
||||||
for (int j = 0; j < height; j++)
|
|
||||||
{
|
|
||||||
float col = image[i][j];
|
|
||||||
|
|
||||||
if (col <= low)
|
|
||||||
{
|
|
||||||
newImage[i][j] = 0;
|
|
||||||
}
|
|
||||||
else if (col >= high)
|
|
||||||
{
|
|
||||||
newImage[i][j] = 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
newImage[i][j] = (col - low) / (high - low);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return newImage;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Color[][][] AnimateTransition(Color[][] image1, Color[][] image2, int frameCount)
|
|
||||||
{
|
|
||||||
Color[][][] animation = new Color[frameCount][][];
|
|
||||||
|
|
||||||
float low = 0;
|
|
||||||
float increment = 1.0f / frameCount;
|
|
||||||
float high = increment;
|
|
||||||
|
|
||||||
float[][] perlinNoise = AdjustLevels(
|
|
||||||
GeneratePerlinNoise(image1.Length, image1[0].Length, 9),
|
|
||||||
0.2f, 0.8f);
|
|
||||||
|
|
||||||
for (int i = 0; i < frameCount; i++)
|
|
||||||
{
|
|
||||||
AdjustLevels(perlinNoise, low, high);
|
|
||||||
float[][] blendMask = AdjustLevels(perlinNoise, low, high);
|
|
||||||
animation[i] = BlendImages(image1, image2, blendMask);
|
|
||||||
//SaveImage(animation[i], "blend_animation" + i + ".png");
|
|
||||||
SaveImage(MapToGrey(blendMask), "blend_mask" + i + ".png");
|
|
||||||
low = high;
|
|
||||||
high += increment;
|
|
||||||
}
|
|
||||||
|
|
||||||
return animation;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
@ -17,13 +17,9 @@ class SoilProperties
|
|||||||
public float Nitrogen;
|
public float Nitrogen;
|
||||||
public float Potassium;
|
public float Potassium;
|
||||||
public float Phosphorous;
|
public float Phosphorous;
|
||||||
public float Rainfall;
|
public float NitrogenDegradeRate = 0.01f;
|
||||||
public float prevRainfall;
|
public float PotassiumDegradeRate = 0.01f;
|
||||||
public float NitrogenDegradeRate = 0.8f / 1.5f;
|
public float PhosphorousDegradeRate = 0.01f;
|
||||||
public float PotassiumDegradeRate = 0.3f / 1.5f;
|
|
||||||
public float PhosphorousDegradeRate = 0.6f / 1.5f;
|
|
||||||
public int Capacity = 80;
|
|
||||||
public int Area;
|
|
||||||
|
|
||||||
public void setSoilProperties()
|
public void setSoilProperties()
|
||||||
{
|
{
|
||||||
@ -49,13 +45,11 @@ class SoilProperties
|
|||||||
soilType = "Clayey";
|
soilType = "Clayey";
|
||||||
}
|
}
|
||||||
Temperature = GetRandomNumber(22, 30);
|
Temperature = GetRandomNumber(22, 30);
|
||||||
Humidity = Temperature * GetRandomNumber(1.9f, 2.1f);
|
Humidity = Temperature * GetRandomNumber(1.9, 2.1);
|
||||||
Moisture = GetRandomNumber(20, 70);
|
Moisture = GetRandomNumber(20, 70);
|
||||||
Nitrogen = GetRandomNumber(4 , 42); //was 4, 60
|
Nitrogen = GetRandomNumber(4 , 55);
|
||||||
Potassium = GetRandomNumber(0.01f, 19); // was 0, 28
|
Potassium = GetRandomNumber(0.01f, 28);
|
||||||
Phosphorous = GetRandomNumber(0.01f, 42); // was 0, 60
|
Phosphorous = GetRandomNumber(0.01f, 60);
|
||||||
prevRainfall = r.Next(247, 3617);
|
|
||||||
Area = r.Next(1, 270000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public float GetRandomNumber(double minimum, double maximum)
|
public float GetRandomNumber(double minimum, double maximum)
|
||||||
|
@ -1,39 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.ML;
|
|
||||||
|
|
||||||
|
|
||||||
static class Engine
|
|
||||||
{
|
|
||||||
private static MLContext mlContext = new MLContext(seed: 1);
|
|
||||||
private static PredictionEngine<ModelInput, ModelOutput> PredictionEngine;
|
|
||||||
private static ModelOutput modelOutput;
|
|
||||||
|
|
||||||
public static void init()
|
|
||||||
{
|
|
||||||
PredictionEngine = MLModel.CreateEngine();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string PredictFertilizer(Crops crop, CropTypes cropTypes)
|
|
||||||
{
|
|
||||||
ModelInput modelInput = new ModelInput
|
|
||||||
{
|
|
||||||
Temperature = crop.getSoilProperties().Temperature,
|
|
||||||
Humidity = crop.getSoilProperties().Humidity,
|
|
||||||
Moisture = crop.getSoilProperties().Moisture,
|
|
||||||
Soil_Type = crop.getSoilProperties().soilType,
|
|
||||||
Crop_Type = cropTypes.CropName,
|
|
||||||
Nitrogen = crop.getSoilProperties().Nitrogen,
|
|
||||||
Potassium = crop.getSoilProperties().Potassium,
|
|
||||||
Phosporous = crop.getSoilProperties().Phosphorous
|
|
||||||
};
|
|
||||||
|
|
||||||
//ModelOutput modelOutput = new ModelOutput();
|
|
||||||
PredictionEngine.Predict(modelInput, ref modelOutput);
|
|
||||||
return modelOutput.Prediction;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -5,38 +5,39 @@ using System.Text;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.ML.Data;
|
using Microsoft.ML.Data;
|
||||||
|
|
||||||
|
namespace Game1.Sources.ML
|
||||||
class BigModelInput
|
|
||||||
{
|
{
|
||||||
[ColumnName("Ca"), LoadColumn(0)]
|
class BigModelInput
|
||||||
public float Ca { get; set; }
|
{
|
||||||
|
[ColumnName("Ca"), LoadColumn(0)]
|
||||||
|
public float Ca { get; set; }
|
||||||
|
|
||||||
[ColumnName("Mg"), LoadColumn(1)]
|
[ColumnName("Mg"), LoadColumn(1)]
|
||||||
public float Mg { get; set; }
|
public float Mg { get; set; }
|
||||||
|
|
||||||
[ColumnName("K"), LoadColumn(2)]
|
[ColumnName("K"), LoadColumn(2)]
|
||||||
public float K { get; set; }
|
public float K { get; set; }
|
||||||
|
|
||||||
[ColumnName("S"), LoadColumn(3)]
|
[ColumnName("S"), LoadColumn(3)]
|
||||||
public float S { get; set; }
|
public float S { get; set; }
|
||||||
|
|
||||||
[ColumnName("N"), LoadColumn(4)]
|
[ColumnName("N"), LoadColumn(4)]
|
||||||
public float N { get; set; }
|
public float N { get; set; }
|
||||||
|
|
||||||
[ColumnName("Lime"), LoadColumn(5)]
|
[ColumnName("Lime"), LoadColumn(5)]
|
||||||
public float Lime { get; set; }
|
public float Lime { get; set; }
|
||||||
|
|
||||||
[ColumnName("C"), LoadColumn(6)]
|
[ColumnName("C"), LoadColumn(6)]
|
||||||
public float C { get; set; }
|
public float C { get; set; }
|
||||||
|
|
||||||
[ColumnName("P"), LoadColumn(7)]
|
[ColumnName("P"), LoadColumn(7)]
|
||||||
public float P { get; set; }
|
public float P { get; set; }
|
||||||
|
|
||||||
[ColumnName("Moisture"), LoadColumn(8)]
|
[ColumnName("Moisture"), LoadColumn(8)]
|
||||||
public float Moisture { get; set; }
|
public float Moisture { get; set; }
|
||||||
|
|
||||||
[ColumnName("Class"), LoadColumn(9)]
|
[ColumnName("Class"), LoadColumn(9)]
|
||||||
public float Class { get; set; }
|
public float Class { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,9 +5,11 @@ using System.Text;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.ML.Data;
|
using Microsoft.ML.Data;
|
||||||
|
|
||||||
class BigModelOutput
|
namespace Game1.Sources.ML
|
||||||
{
|
{
|
||||||
[ColumnName("PredictedLabel")]
|
class BigModelOutput
|
||||||
public float Prediction { get; set; }
|
{
|
||||||
|
[ColumnName("PredictedLabel")]
|
||||||
|
public float Prediction { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,34 +6,35 @@ using System.Threading.Tasks;
|
|||||||
using Microsoft.ML;
|
using Microsoft.ML;
|
||||||
using Microsoft.ML.Data;
|
using Microsoft.ML.Data;
|
||||||
|
|
||||||
|
namespace Game1.Sources.ML
|
||||||
class ModelInput
|
|
||||||
{
|
{
|
||||||
[ColumnName("Temperature"), LoadColumn(0)]
|
class ModelInput
|
||||||
public float Temperature { get; set; }
|
{
|
||||||
|
[ColumnName("Temperature"), LoadColumn(0)]
|
||||||
|
public float Temperature { get; set; }
|
||||||
|
|
||||||
[ColumnName("Humidity"), LoadColumn(1)]
|
[ColumnName("Humidity"), LoadColumn(1)]
|
||||||
public float Humidity { get; set; }
|
public float Humidity { get; set; }
|
||||||
|
|
||||||
[ColumnName("Moisture"), LoadColumn(2)]
|
[ColumnName("Moisture"), LoadColumn(2)]
|
||||||
public float Moisture { get; set; }
|
public float Moisture { get; set; }
|
||||||
|
|
||||||
[ColumnName("Soil_Type"), LoadColumn(3)]
|
[ColumnName("Soil_Type"), LoadColumn(3)]
|
||||||
public String Soil_Type { get; set; }
|
public String Soil_Type { get; set; }
|
||||||
|
|
||||||
[ColumnName("Crop_Type"), LoadColumn(4)]
|
[ColumnName("Crop_Type"), LoadColumn(4)]
|
||||||
public String Crop_Type { get; set; }
|
public String Crop_Type { get; set; }
|
||||||
|
|
||||||
[ColumnName("Nitrogen"), LoadColumn(5)]
|
[ColumnName("Nitrogen"), LoadColumn(5)]
|
||||||
public float Nitrogen { get; set; }
|
public float Nitrogen { get; set; }
|
||||||
|
|
||||||
[ColumnName("Potassium"), LoadColumn(6)]
|
[ColumnName("Potassium"), LoadColumn(6)]
|
||||||
public float Potassium { get; set; }
|
public float Potassium { get; set; }
|
||||||
|
|
||||||
[ColumnName("Phosphorous"), LoadColumn(7)]
|
[ColumnName("Phosphorous"), LoadColumn(7)]
|
||||||
public float Phosporous { get; set; }
|
public float Phosporous { get; set; }
|
||||||
|
|
||||||
[ColumnName("Fertilizer_Name"), LoadColumn(8)]
|
[ColumnName("Fertilizer_Name"), LoadColumn(8)]
|
||||||
public String Fertilizer_Name { get; set; }
|
public String Fertilizer_Name { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,11 +5,13 @@ using System.Text;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.ML.Data;
|
using Microsoft.ML.Data;
|
||||||
|
|
||||||
class ModelOutput
|
namespace Game1.Sources.ML
|
||||||
{
|
{
|
||||||
[ColumnName("PredictedLabel")]
|
class ModelOutput
|
||||||
public String Prediction { get; set; }
|
{
|
||||||
//public float[] Score { get; set; }
|
[ColumnName("PredictedLabel")]
|
||||||
|
public String Prediction { get; set; }
|
||||||
|
//public float[] Score { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,186 +1,169 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.ML;
|
using Microsoft.ML;
|
||||||
using Microsoft.ML.Data;
|
using Microsoft.ML.Data;
|
||||||
using Microsoft.ML.Trainers.LightGbm;
|
using Microsoft.ML.Trainers.LightGbm;
|
||||||
|
|
||||||
|
namespace Game1.Sources.ML
|
||||||
class MLModel
|
|
||||||
{
|
{
|
||||||
private static MLContext mlContext = new MLContext(seed: 1);
|
class MLModel
|
||||||
|
|
||||||
private static string path_base = FindPath();
|
|
||||||
|
|
||||||
private static string path = System.IO.Path.Combine(path_base, "Content/ML/Fertilizer_Prediction.csv");
|
|
||||||
private static string modelpath = System.IO.Path.Combine(path_base, "Content/ML/MLmodel");
|
|
||||||
private static string report = System.IO.Path.Combine(path_base, "Content/ML/report");
|
|
||||||
|
|
||||||
private static string pathBig = System.IO.Path.Combine(path_base, "Content/ML/BigFertPredict.csv");
|
|
||||||
private static string modelpathBig = System.IO.Path.Combine(path_base, "Content/ML/MLmodelBig");
|
|
||||||
private static string reportBig = System.IO.Path.Combine(path_base, "Content/ML/report_BigModel");
|
|
||||||
|
|
||||||
// Loading data, creatin and saving ML model for smaller dataset (100)
|
|
||||||
public static void CreateModel()
|
|
||||||
{
|
{
|
||||||
|
private static MLContext mlContext = new MLContext(seed: 1);
|
||||||
|
private static string path = "C:/Users/Oskar/source/repos/PotatoPlanFinal/Game1/Content/ML/Fertilizer_Prediction.csv";
|
||||||
|
private static string modelpath = "C:/Users/Oskar/source/repos/PotatoPlanFinal/Game1/Content/ML/MLmodel";
|
||||||
|
private static string report = "C:/Users/Oskar/source/repos/PotatoPlanFinal/Game1/Content/ML/report";
|
||||||
|
private static string pathBig = "C:/Users/Oskar/source/repos/PotatoPlanFinal/Game1/Content/ML/BigFertPredict.csv";
|
||||||
|
private static string modelpathBig = "C:/Users/Oskar/source/repos/PotatoPlanFinal/Game1/Content/ML/MLmodelBig";
|
||||||
|
private static string reportBig = "C:/Users/Oskar/source/repos/PotatoPlanFinal/Game1/Content/ML/report_BigModel";
|
||||||
|
|
||||||
IDataView trainingDataView = mlContext.Data.LoadFromTextFile<ModelInput>(
|
// Loading data, creatin and saving ML model for smaller dataset (100)
|
||||||
path: path,
|
public static void CreateModel()
|
||||||
hasHeader: true,
|
|
||||||
separatorChar: ',',
|
|
||||||
allowQuoting: true,
|
|
||||||
allowSparse: false);
|
|
||||||
|
|
||||||
ModelInput sample = mlContext.Data.CreateEnumerable<ModelInput>(trainingDataView, false).ElementAt(0);
|
|
||||||
ITransformer MLModel = BuildAndTrain(mlContext, trainingDataView, sample, report);
|
|
||||||
SaveModel(mlContext, MLModel, modelpath, trainingDataView.Schema);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ... for bigger dataset (1600)
|
|
||||||
public static void CreateBigModel()
|
|
||||||
{
|
|
||||||
|
|
||||||
IDataView trainingDataView = mlContext.Data.LoadFromTextFile<BigModelInput>(
|
|
||||||
path: pathBig,
|
|
||||||
hasHeader: true,
|
|
||||||
separatorChar: ',',
|
|
||||||
allowQuoting: true,
|
|
||||||
allowSparse: false);
|
|
||||||
|
|
||||||
BigModelInput sample = mlContext.Data.CreateEnumerable<BigModelInput>(trainingDataView, false).ElementAt(0);
|
|
||||||
ITransformer MLModel = BuildAndTrain(mlContext, trainingDataView, sample, reportBig);
|
|
||||||
SaveModel(mlContext, MLModel, modelpathBig, trainingDataView.Schema);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Building and training ML model, very small dataset (100 entries)
|
|
||||||
public static ITransformer BuildAndTrain(MLContext mLContext, IDataView trainingDataView, ModelInput sample, string reportPath)
|
|
||||||
{
|
|
||||||
|
|
||||||
var options = new LightGbmMulticlassTrainer.Options
|
|
||||||
{
|
{
|
||||||
MaximumBinCountPerFeature = 8,
|
|
||||||
LearningRate = 0.00025,
|
|
||||||
NumberOfIterations = 40000,
|
|
||||||
NumberOfLeaves = 10,
|
|
||||||
LabelColumnName = "Fertilizer_NameF",
|
|
||||||
FeatureColumnName = "Features",
|
|
||||||
|
|
||||||
Booster = new DartBooster.Options()
|
IDataView trainingDataView = mlContext.Data.LoadFromTextFile<ModelInput>(
|
||||||
{
|
path: path,
|
||||||
MaximumTreeDepth = 10
|
hasHeader: true,
|
||||||
}
|
separatorChar: ',',
|
||||||
};
|
allowQuoting: true,
|
||||||
|
allowSparse: false);
|
||||||
|
|
||||||
var pipeline = mlContext.Transforms
|
ModelInput sample = mlContext.Data.CreateEnumerable<ModelInput>(trainingDataView, false).ElementAt(0);
|
||||||
.Text.FeaturizeText("Soil_TypeF", "Soil_Type")
|
ITransformer MLModel = BuildAndTrain(mlContext, trainingDataView, sample, report);
|
||||||
.Append(mlContext.Transforms.Text.FeaturizeText("Crop_TypeF", "Crop_Type"))
|
SaveModel(mlContext, MLModel, modelpath, trainingDataView.Schema);
|
||||||
.Append(mlContext.Transforms.Concatenate("Features", "Temperature", "Humidity", "Moisture", "Soil_TypeF", "Crop_TypeF", "Nitrogen", "Potassium", "Phosphorous"))
|
|
||||||
.Append(mlContext.Transforms.Conversion.MapValueToKey("Fertilizer_NameF", "Fertilizer_Name"), TransformerScope.TrainTest)
|
|
||||||
.AppendCacheCheckpoint(mLContext)
|
|
||||||
.Append(mLContext.MulticlassClassification.Trainers.LightGbm(options))
|
|
||||||
.Append(mlContext.Transforms.Conversion.MapKeyToValue("PredictedLabel", "PredictedLabel"));
|
|
||||||
|
|
||||||
Evaluate(mlContext, trainingDataView, pipeline, 10, reportPath, "Fertilizer_NameF");
|
|
||||||
ITransformer MLModel = pipeline.Fit(trainingDataView);
|
|
||||||
|
|
||||||
return MLModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Building and training ML model, moderate size dataset (1600 entries)
|
|
||||||
public static ITransformer BuildAndTrain(MLContext mLContext, IDataView trainingDataView, BigModelInput sample, string reportPath)
|
|
||||||
{
|
|
||||||
|
|
||||||
var options = new LightGbmMulticlassTrainer.Options
|
|
||||||
{
|
|
||||||
MaximumBinCountPerFeature = 10,
|
|
||||||
LearningRate = 0.001,
|
|
||||||
NumberOfIterations = 10000,
|
|
||||||
NumberOfLeaves = 12,
|
|
||||||
LabelColumnName = "ClassF",
|
|
||||||
FeatureColumnName = "Features",
|
|
||||||
|
|
||||||
Booster = new DartBooster.Options()
|
|
||||||
{
|
|
||||||
MaximumTreeDepth = 12
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var pipeline = mlContext.Transforms
|
|
||||||
.Concatenate("Features", "Ca", "Mg", "K", "S", "N", "Lime", "C", "P", "Moisture")
|
|
||||||
.Append(mLContext.Transforms.NormalizeMinMax("Features"))
|
|
||||||
.Append(mlContext.Transforms.Conversion.MapValueToKey("ClassF", "Class"), TransformerScope.TrainTest)
|
|
||||||
.AppendCacheCheckpoint(mLContext)
|
|
||||||
.Append(mLContext.MulticlassClassification.Trainers.LightGbm(options))
|
|
||||||
.Append(mlContext.Transforms.Conversion.MapKeyToValue("PredictedLabel", "PredictedLabel"));
|
|
||||||
|
|
||||||
Evaluate(mlContext, trainingDataView, pipeline, 8, reportPath, "ClassF");
|
|
||||||
ITransformer MLModel = pipeline.Fit(trainingDataView);
|
|
||||||
|
|
||||||
return MLModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ITransformer TrainModel(MLContext mlContext, IDataView trainingDataView, IEstimator<ITransformer> trainingPipeline)
|
|
||||||
{
|
|
||||||
ITransformer model = trainingPipeline.Fit(trainingDataView);
|
|
||||||
return model;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate and save results to a text file
|
|
||||||
public static void Evaluate(MLContext mlContext, IDataView trainingDataView, IEstimator<ITransformer> trainingPipeline, int folds, string reportPath, string labelColumnName)
|
|
||||||
{
|
|
||||||
var crossVal = mlContext.MulticlassClassification.CrossValidate(trainingDataView, trainingPipeline, numberOfFolds: folds, labelColumnName: labelColumnName);
|
|
||||||
|
|
||||||
var metricsInMultipleFolds = crossVal.Select(r => r.Metrics);
|
|
||||||
|
|
||||||
var MicroAccuracyValues = metricsInMultipleFolds.Select(m => m.MicroAccuracy);
|
|
||||||
var LogLossValues = metricsInMultipleFolds.Select(m => m.LogLoss);
|
|
||||||
var LogLossReductionValues = metricsInMultipleFolds.Select(m => m.LogLossReduction);
|
|
||||||
string MicroAccuracyAverage = MicroAccuracyValues.Average().ToString("0.######");
|
|
||||||
string LogLossAvg = LogLossValues.Average().ToString("0.######");
|
|
||||||
string LogLossReductionAvg = LogLossReductionValues.Average().ToString("0.######");
|
|
||||||
|
|
||||||
var report = File.CreateText(reportPath);
|
|
||||||
report.Write("Micro Accuracy: " + MicroAccuracyAverage +'\n'+ "LogLoss Average: " + LogLossAvg +'\n'+ "LogLoss Reduction: " + LogLossReductionAvg, 0, 0);
|
|
||||||
report.Flush();
|
|
||||||
report.Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static void SaveModel(MLContext mlContext, ITransformer Model, string modelPath, DataViewSchema modelInputSchema)
|
|
||||||
{
|
|
||||||
mlContext.Model.Save(Model, modelInputSchema, modelPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ITransformer LoadModel(bool isBig)
|
|
||||||
{
|
|
||||||
if (isBig)
|
|
||||||
return mlContext.Model.Load(modelpathBig, out DataViewSchema inputSchema);
|
|
||||||
else
|
|
||||||
return mlContext.Model.Load(modelpath, out DataViewSchema inputSchema);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static PredictionEngine<ModelInput, ModelOutput> CreateEngine()
|
|
||||||
{
|
|
||||||
ITransformer mlModel = LoadModel(false);
|
|
||||||
return mlContext.Model.CreatePredictionEngine<ModelInput, ModelOutput>(mlModel);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string FindPath()
|
|
||||||
{
|
|
||||||
string path = System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location).ToString();
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
path = Directory.GetParent(path).ToString();
|
|
||||||
if (path.EndsWith("\\Game1"))
|
|
||||||
{
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ... for bigger dataset (1600)
|
||||||
|
public static void CreateBigModel()
|
||||||
|
{
|
||||||
|
|
||||||
|
IDataView trainingDataView = mlContext.Data.LoadFromTextFile<BigModelInput>(
|
||||||
|
path: pathBig,
|
||||||
|
hasHeader: true,
|
||||||
|
separatorChar: ',',
|
||||||
|
allowQuoting: true,
|
||||||
|
allowSparse: false);
|
||||||
|
|
||||||
|
BigModelInput sample = mlContext.Data.CreateEnumerable<BigModelInput>(trainingDataView, false).ElementAt(0);
|
||||||
|
ITransformer MLModel = BuildAndTrain(mlContext, trainingDataView, sample, reportBig);
|
||||||
|
SaveModel(mlContext, MLModel, modelpathBig, trainingDataView.Schema);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Building and training ML model, very small dataset (100 entries)
|
||||||
|
public static ITransformer BuildAndTrain(MLContext mLContext, IDataView trainingDataView, ModelInput sample, string reportPath)
|
||||||
|
{
|
||||||
|
|
||||||
|
var options = new LightGbmMulticlassTrainer.Options
|
||||||
|
{
|
||||||
|
MaximumBinCountPerFeature = 8,
|
||||||
|
LearningRate = 0.00025,
|
||||||
|
NumberOfIterations = 40000,
|
||||||
|
NumberOfLeaves = 10,
|
||||||
|
LabelColumnName = "Fertilizer_NameF",
|
||||||
|
FeatureColumnName = "Features",
|
||||||
|
|
||||||
|
Booster = new DartBooster.Options()
|
||||||
|
{
|
||||||
|
MaximumTreeDepth = 10
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var pipeline = mlContext.Transforms
|
||||||
|
.Text.FeaturizeText("Soil_TypeF", "Soil_Type")
|
||||||
|
.Append(mlContext.Transforms.Text.FeaturizeText("Crop_TypeF", "Crop_Type"))
|
||||||
|
.Append(mlContext.Transforms.Concatenate("Features", "Temperature", "Humidity", "Moisture", "Soil_TypeF", "Crop_TypeF", "Nitrogen", "Potassium", "Phosphorous"))
|
||||||
|
.Append(mLContext.Transforms.NormalizeMinMax("Features"))
|
||||||
|
.Append(mlContext.Transforms.Conversion.MapValueToKey("Fertilizer_NameF", "Fertilizer_Name"), TransformerScope.TrainTest)
|
||||||
|
.AppendCacheCheckpoint(mLContext)
|
||||||
|
.Append(mLContext.MulticlassClassification.Trainers.LightGbm(options))
|
||||||
|
.Append(mlContext.Transforms.Conversion.MapKeyToValue("PredictedLabel", "PredictedLabel"));
|
||||||
|
|
||||||
|
Evaluate(mlContext, trainingDataView, pipeline, 10, reportPath, "Fertilizer_NameF");
|
||||||
|
ITransformer MLModel = pipeline.Fit(trainingDataView);
|
||||||
|
|
||||||
|
return MLModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Building and training ML model, moderate size dataset (1600 entries)
|
||||||
|
public static ITransformer BuildAndTrain(MLContext mLContext, IDataView trainingDataView, BigModelInput sample, string reportPath)
|
||||||
|
{
|
||||||
|
|
||||||
|
var options = new LightGbmMulticlassTrainer.Options
|
||||||
|
{
|
||||||
|
MaximumBinCountPerFeature = 10,
|
||||||
|
LearningRate = 0.001,
|
||||||
|
NumberOfIterations = 10000,
|
||||||
|
NumberOfLeaves = 12,
|
||||||
|
LabelColumnName = "ClassF",
|
||||||
|
FeatureColumnName = "Features",
|
||||||
|
|
||||||
|
Booster = new DartBooster.Options()
|
||||||
|
{
|
||||||
|
MaximumTreeDepth = 12
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var pipeline = mlContext.Transforms
|
||||||
|
.Concatenate("Features", "Ca", "Mg", "K", "S", "N", "Lime", "C", "P", "Moisture")
|
||||||
|
.Append(mLContext.Transforms.NormalizeMinMax("Features"))
|
||||||
|
.Append(mlContext.Transforms.Conversion.MapValueToKey("ClassF", "Class"), TransformerScope.TrainTest)
|
||||||
|
.AppendCacheCheckpoint(mLContext)
|
||||||
|
.Append(mLContext.MulticlassClassification.Trainers.LightGbm(options))
|
||||||
|
.Append(mlContext.Transforms.Conversion.MapKeyToValue("PredictedLabel", "PredictedLabel"));
|
||||||
|
|
||||||
|
Evaluate(mlContext, trainingDataView, pipeline, 8, reportPath, "ClassF");
|
||||||
|
ITransformer MLModel = pipeline.Fit(trainingDataView);
|
||||||
|
|
||||||
|
return MLModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ITransformer TrainModel(MLContext mlContext, IDataView trainingDataView, IEstimator<ITransformer> trainingPipeline)
|
||||||
|
{
|
||||||
|
ITransformer model = trainingPipeline.Fit(trainingDataView);
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Evaluate and save results to a text file
|
||||||
|
public static void Evaluate(MLContext mlContext, IDataView trainingDataView, IEstimator<ITransformer> trainingPipeline, int folds, string reportPath, string labelColumnName)
|
||||||
|
{
|
||||||
|
var crossVal = mlContext.MulticlassClassification.CrossValidate(trainingDataView, trainingPipeline, numberOfFolds: folds, labelColumnName: labelColumnName);
|
||||||
|
|
||||||
|
var metricsInMultipleFolds = crossVal.Select(r => r.Metrics);
|
||||||
|
|
||||||
|
var MicroAccuracyValues = metricsInMultipleFolds.Select(m => m.MicroAccuracy);
|
||||||
|
var LogLossValues = metricsInMultipleFolds.Select(m => m.LogLoss);
|
||||||
|
var LogLossReductionValues = metricsInMultipleFolds.Select(m => m.LogLossReduction);
|
||||||
|
string MicroAccuracyAverage = MicroAccuracyValues.Average().ToString("0.######");
|
||||||
|
string LogLossAvg = LogLossValues.Average().ToString("0.######");
|
||||||
|
string LogLossReductionAvg = LogLossReductionValues.Average().ToString("0.######");
|
||||||
|
|
||||||
|
var report = File.CreateText(reportPath);
|
||||||
|
report.Write("Micro Accuracy: " + MicroAccuracyAverage +'\n'+ "LogLoss Average: " + LogLossAvg +'\n'+ "LogLoss Reduction: " + LogLossReductionAvg, 0, 0);
|
||||||
|
report.Flush();
|
||||||
|
report.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void SaveModel(MLContext mlContext, ITransformer Model, string modelPath, DataViewSchema modelInputSchema)
|
||||||
|
{
|
||||||
|
mlContext.Model.Save(Model, modelInputSchema, modelPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ITransformer LoadModel(bool isBig)
|
||||||
|
{
|
||||||
|
if (isBig)
|
||||||
|
return mlContext.Model.Load(modelpathBig, out DataViewSchema inputSchema);
|
||||||
|
else
|
||||||
|
return mlContext.Model.Load(modelpath, out DataViewSchema inputSchema);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Microsoft.ML.PredictionEngine<ModelInput, ModelOutput> CreateEngine()
|
||||||
|
{
|
||||||
|
ITransformer mlModel = LoadModel(false);
|
||||||
|
return mlContext.Model.CreatePredictionEngine<ModelInput, ModelOutput>(mlModel);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,24 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.ML.Data;
|
|
||||||
|
|
||||||
namespace Game1.Sources.ML_Joel
|
|
||||||
{
|
|
||||||
class Input
|
|
||||||
{
|
|
||||||
[ColumnName("Season"), LoadColumn(0)]
|
|
||||||
public String Season { get; set; }
|
|
||||||
|
|
||||||
[ColumnName("Crop"), LoadColumn(1)]
|
|
||||||
public String Crop { get; set; }
|
|
||||||
|
|
||||||
[ColumnName("Rainfall"), LoadColumn(2)]
|
|
||||||
public float Rainfall { get; set; }
|
|
||||||
|
|
||||||
[ColumnName("Production"), LoadColumn(3)]
|
|
||||||
public float Production { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,27 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.ML.Data;
|
|
||||||
|
|
||||||
namespace Game1.Sources.ML_Joel
|
|
||||||
{
|
|
||||||
class InputArea
|
|
||||||
{
|
|
||||||
[ColumnName("Season"), LoadColumn(0)]
|
|
||||||
public String Season { get; set; }
|
|
||||||
|
|
||||||
[ColumnName("Crop"), LoadColumn(1)]
|
|
||||||
public String Crop { get; set; }
|
|
||||||
|
|
||||||
[ColumnName("Area"), LoadColumn(2)]
|
|
||||||
public float Area { get; set; }
|
|
||||||
|
|
||||||
[ColumnName("Rainfall"), LoadColumn(3)]
|
|
||||||
public float Rainfall { get; set; }
|
|
||||||
|
|
||||||
[ColumnName("Production"), LoadColumn(4)]
|
|
||||||
public float Production { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.ML.Data;
|
|
||||||
|
|
||||||
namespace Game1.Sources.ML_Joel
|
|
||||||
{
|
|
||||||
class Output
|
|
||||||
{
|
|
||||||
//[ColumnName("PredictedLabel")]
|
|
||||||
public float Prediction { get; set; }
|
|
||||||
public float Score { get; set; }
|
|
||||||
|
|
||||||
//[ColumnName("Score")]
|
|
||||||
// public float[] Score { get; set; }
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.ML.Data;
|
|
||||||
|
|
||||||
namespace Game1.Sources.ML_Joel
|
|
||||||
{
|
|
||||||
class OutputArea
|
|
||||||
{
|
|
||||||
public float Prediction { get; set; }
|
|
||||||
public float Score { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,55 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.ML;
|
|
||||||
|
|
||||||
|
|
||||||
namespace Game1.Sources.ML_Joel
|
|
||||||
{
|
|
||||||
static class Engine
|
|
||||||
{
|
|
||||||
private static MLContext mlContext = new MLContext(seed: 1);
|
|
||||||
private static PredictionEngine<Input, Output> PredictionEngine;
|
|
||||||
private static PredictionEngine<InputArea, OutputArea> PredictionEngineArea;
|
|
||||||
private static OutputArea modelOutput;
|
|
||||||
|
|
||||||
|
|
||||||
public static void CreateModel()
|
|
||||||
{
|
|
||||||
Model.CreateModel();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void CreateModelArea()
|
|
||||||
{
|
|
||||||
Model.CreateModelArea();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void init()
|
|
||||||
{
|
|
||||||
PredictionEngine = Model.CreateEngine();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void initArea()
|
|
||||||
{
|
|
||||||
PredictionEngineArea = Model.CreateEngineArea();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static float PredictProductionwithRainfall(SoilProperties soilProperties, DayNightCycle Time)
|
|
||||||
{
|
|
||||||
InputArea modelInput = new InputArea
|
|
||||||
{
|
|
||||||
Season = Time.getTimeOfYear(),
|
|
||||||
Area = soilProperties.Area,
|
|
||||||
Rainfall = soilProperties.prevRainfall,
|
|
||||||
};
|
|
||||||
|
|
||||||
//OutputArea modelOutput = new OutputArea();
|
|
||||||
PredictionEngineArea.Predict(modelInput, ref modelOutput);
|
|
||||||
return modelOutput.Score;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,190 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.ML;
|
|
||||||
using Microsoft.ML.Data;
|
|
||||||
using Microsoft.ML.Trainers.LightGbm;
|
|
||||||
|
|
||||||
namespace Game1.Sources.ML_Joel
|
|
||||||
{
|
|
||||||
class Model
|
|
||||||
{
|
|
||||||
private static MLContext mlContext = new MLContext(seed: 1);
|
|
||||||
|
|
||||||
private static string path_base = FindPath();
|
|
||||||
|
|
||||||
private static string path = System.IO.Path.Combine(path_base, "Content/ML/Rainfall.csv");
|
|
||||||
private static string modelpath = System.IO.Path.Combine(path_base, "Content/ML/MLmodel_Joel");
|
|
||||||
private static string report = System.IO.Path.Combine(path_base, "Content/ML/report_Joel");
|
|
||||||
|
|
||||||
private static string path_area = System.IO.Path.Combine(path_base, "Content/ML/Rainfall_area.csv");
|
|
||||||
private static string modelpath_area = System.IO.Path.Combine(path_base, "Content/ML/MLmodel_Joel_area");
|
|
||||||
private static string report_area = System.IO.Path.Combine(path_base, "Content/ML/report_Joel_area");
|
|
||||||
|
|
||||||
// Loading data, creatin and saving ML model for smaller dataset (100)
|
|
||||||
public static void CreateModel()
|
|
||||||
{
|
|
||||||
|
|
||||||
IDataView trainingDataView = mlContext.Data.LoadFromTextFile<Input>(
|
|
||||||
path: path,
|
|
||||||
hasHeader: true,
|
|
||||||
separatorChar: ',',
|
|
||||||
allowQuoting: true,
|
|
||||||
allowSparse: false);
|
|
||||||
|
|
||||||
var splitData = mlContext.Data.TrainTestSplit(trainingDataView, testFraction: 0.2);
|
|
||||||
trainingDataView = splitData.TrainSet;
|
|
||||||
IDataView testDataView = splitData.TestSet;
|
|
||||||
Input sample = mlContext.Data.CreateEnumerable<Input>(trainingDataView, false).ElementAt(0);
|
|
||||||
ITransformer MLModel = BuildAndTrain(mlContext, trainingDataView, testDataView, sample, report);
|
|
||||||
SaveModel(mlContext, MLModel, modelpath, trainingDataView.Schema);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Building and training ML model
|
|
||||||
public static ITransformer BuildAndTrain(MLContext mLContext, IDataView trainingDataView, IDataView testDataView, Input sample, string reportPath)
|
|
||||||
{
|
|
||||||
|
|
||||||
var options = new LightGbmRegressionTrainer.Options
|
|
||||||
{
|
|
||||||
MaximumBinCountPerFeature = 40,
|
|
||||||
LearningRate = 0.00020,
|
|
||||||
NumberOfIterations = 20000,
|
|
||||||
NumberOfLeaves = 55,
|
|
||||||
LabelColumnName = "Production",
|
|
||||||
FeatureColumnName = "Features",
|
|
||||||
|
|
||||||
Booster = new DartBooster.Options()
|
|
||||||
{
|
|
||||||
MaximumTreeDepth = 10
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var pipeline = mlContext.Transforms
|
|
||||||
.Text.FeaturizeText("SeasonF", "Season")
|
|
||||||
.Append(mlContext.Transforms.Text.FeaturizeText("CropF", "Crop"))
|
|
||||||
.Append(mlContext.Transforms.Concatenate("Features", "SeasonF", "CropF", "Rainfall"))
|
|
||||||
.AppendCacheCheckpoint(mLContext)
|
|
||||||
.Append(mLContext.Regression.Trainers.LightGbm(options));
|
|
||||||
|
|
||||||
ITransformer MLModel = pipeline.Fit(trainingDataView);
|
|
||||||
var testEval = MLModel.Transform(testDataView);
|
|
||||||
|
|
||||||
Evaluate(mlContext, testEval, pipeline, 10, reportPath, "Production");
|
|
||||||
|
|
||||||
return MLModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void CreateModelArea()
|
|
||||||
{
|
|
||||||
|
|
||||||
IDataView trainingDataView = mlContext.Data.LoadFromTextFile<InputArea>(
|
|
||||||
path: path_area,
|
|
||||||
hasHeader: true,
|
|
||||||
separatorChar: ',',
|
|
||||||
allowQuoting: true,
|
|
||||||
allowSparse: false);
|
|
||||||
|
|
||||||
var splitData = mlContext.Data.TrainTestSplit(trainingDataView, testFraction: 0.2);
|
|
||||||
trainingDataView = splitData.TrainSet;
|
|
||||||
IDataView testDataView = splitData.TestSet;
|
|
||||||
ITransformer MLModel = BuildAndTrainArea(mlContext, trainingDataView, testDataView, report_area);
|
|
||||||
SaveModel(mlContext, MLModel, modelpath_area, trainingDataView.Schema);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Building and training ML model
|
|
||||||
public static ITransformer BuildAndTrainArea(MLContext mLContext, IDataView trainingDataView, IDataView testDataView, string reportPath)
|
|
||||||
{
|
|
||||||
|
|
||||||
var options = new LightGbmRegressionTrainer.Options
|
|
||||||
{
|
|
||||||
MaximumBinCountPerFeature = 40,
|
|
||||||
LearningRate = 0.00020,
|
|
||||||
NumberOfIterations = 20000,
|
|
||||||
NumberOfLeaves = 55,
|
|
||||||
LabelColumnName = "Production",
|
|
||||||
FeatureColumnName = "Features",
|
|
||||||
|
|
||||||
Booster = new DartBooster.Options()
|
|
||||||
{
|
|
||||||
MaximumTreeDepth = 10
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var pipeline = mlContext.Transforms
|
|
||||||
.Text.FeaturizeText("SeasonF", "Season")
|
|
||||||
.Append(mlContext.Transforms.Text.FeaturizeText("CropF", "Crop"))
|
|
||||||
.Append(mlContext.Transforms.Concatenate("Features", "SeasonF", "CropF", "Area", "Rainfall"))
|
|
||||||
.AppendCacheCheckpoint(mLContext)
|
|
||||||
.Append(mLContext.Regression.Trainers.LightGbm(options));
|
|
||||||
|
|
||||||
ITransformer MLModel = pipeline.Fit(trainingDataView);
|
|
||||||
var testEval = MLModel.Transform(testDataView);
|
|
||||||
|
|
||||||
Evaluate(mlContext, testEval, pipeline, 10, reportPath, "Production");
|
|
||||||
|
|
||||||
return MLModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ITransformer TrainModel(MLContext mlContext, IDataView trainingDataView, IEstimator<ITransformer> trainingPipeline)
|
|
||||||
{
|
|
||||||
ITransformer model = trainingPipeline.Fit(trainingDataView);
|
|
||||||
return model;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate and save results to a text file
|
|
||||||
public static void Evaluate(MLContext mlContext, IDataView trainingDataView, IEstimator<ITransformer> trainingPipeline, int folds, string reportPath, string labelColumnName)
|
|
||||||
{
|
|
||||||
var eval = mlContext.Regression.Evaluate(trainingDataView, labelColumnName: labelColumnName);
|
|
||||||
|
|
||||||
var report = File.CreateText(reportPath);
|
|
||||||
report.Write("Mean Absolute Error: " + eval.MeanAbsoluteError + '\n' + "R Squared: " + eval.RSquared, 0, 0);
|
|
||||||
report.Flush();
|
|
||||||
report.Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static void SaveModel(MLContext mlContext, ITransformer Model, string modelPath, DataViewSchema modelInputSchema)
|
|
||||||
{
|
|
||||||
mlContext.Model.Save(Model, modelInputSchema, modelPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ITransformer LoadModel()
|
|
||||||
{
|
|
||||||
return mlContext.Model.Load(modelpath, out DataViewSchema inputSchema);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static PredictionEngine<Input, Output> CreateEngine()
|
|
||||||
{
|
|
||||||
ITransformer mlModel = LoadModel();
|
|
||||||
return mlContext.Model.CreatePredictionEngine<Input, Output>(mlModel);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ITransformer LoadModelArea()
|
|
||||||
{
|
|
||||||
return mlContext.Model.Load(modelpath_area, out DataViewSchema inputSchema);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static PredictionEngine<InputArea, OutputArea> CreateEngineArea()
|
|
||||||
{
|
|
||||||
ITransformer mlModel = LoadModelArea();
|
|
||||||
return mlContext.Model.CreatePredictionEngine<InputArea, OutputArea>(mlModel);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string FindPath()
|
|
||||||
{
|
|
||||||
string path = System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location).ToString();
|
|
||||||
while(true)
|
|
||||||
{
|
|
||||||
path = Directory.GetParent(path).ToString();
|
|
||||||
if (path.EndsWith("\\Game1"))
|
|
||||||
{
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -8,30 +8,22 @@ using Microsoft.Xna.Framework;
|
|||||||
class DayNightCycle
|
class DayNightCycle
|
||||||
{
|
{
|
||||||
private bool Time = true;
|
private bool Time = true;
|
||||||
private bool Day = true;
|
|
||||||
private int nightTime = 0;
|
private int nightTime = 0;
|
||||||
private int dayTime = 0;
|
private int dayTime = 0;
|
||||||
private int lengthOfDay = 20000;
|
private int lengthOfDay = 20000;
|
||||||
private int lengthOfNight = 20000;
|
private int lengthOfNight = 20000;
|
||||||
private int Days = 1;
|
private int Days = 1;
|
||||||
private int DaysOfYear = 0;
|
|
||||||
private int speed = 1;
|
|
||||||
private bool nextDay = true;
|
|
||||||
|
|
||||||
|
|
||||||
public void updateTime(int Speed)
|
public void updateTime(int Speed)
|
||||||
{
|
{
|
||||||
speed = Speed;
|
|
||||||
Time = false;
|
|
||||||
for (int i = 0; i < Speed; i++)
|
for (int i = 0; i < Speed; i++)
|
||||||
{
|
{
|
||||||
if (Day)
|
if (Time)
|
||||||
{
|
{
|
||||||
dayTime++;
|
dayTime++;
|
||||||
if (dayTime == lengthOfDay)
|
if (dayTime == lengthOfDay)
|
||||||
{
|
{
|
||||||
Time = false;
|
Time = false;
|
||||||
Day = false;
|
|
||||||
dayTime = 0;
|
dayTime = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -41,47 +33,32 @@ class DayNightCycle
|
|||||||
if (nightTime == lengthOfNight)
|
if (nightTime == lengthOfNight)
|
||||||
{
|
{
|
||||||
Time = true;
|
Time = true;
|
||||||
Day = true;
|
|
||||||
nightTime = 0;
|
nightTime = 0;
|
||||||
Days++;
|
Days++;
|
||||||
DaysOfYear++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (DaysOfYear == 48)
|
|
||||||
{
|
|
||||||
DaysOfYear = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Season:
|
public string getDayNight()
|
||||||
//0 - Whole Year
|
|
||||||
//1 - Spring
|
|
||||||
//2 - Summer
|
|
||||||
//3 - Autumn
|
|
||||||
//4 - Winter
|
|
||||||
|
|
||||||
public string getTimeOfYear()
|
|
||||||
{
|
{
|
||||||
if (DaysOfYear < 12)
|
if (Time)
|
||||||
return "Spring";
|
{
|
||||||
else if (DaysOfYear < 24)
|
return "Day";
|
||||||
return "Summer";
|
}
|
||||||
else if (DaysOfYear < 36)
|
|
||||||
return "Autumn";
|
|
||||||
else
|
else
|
||||||
return "Winter";
|
{
|
||||||
|
return "Night";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Color GetTimeOfDay()
|
public Color GetTimeOfDay()
|
||||||
{
|
{
|
||||||
int blue, red, brightness, green, potatorate = 255;
|
int blue, red, brightness;
|
||||||
if (nightTime == 0 && dayTime == 0)
|
if (nightTime == 0 && dayTime == 0)
|
||||||
{
|
{
|
||||||
red = 1;
|
red = 1;
|
||||||
blue = 1;
|
blue = 1;
|
||||||
green = 1;
|
|
||||||
brightness = 1;
|
brightness = 1;
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -89,29 +66,20 @@ class DayNightCycle
|
|||||||
{
|
{
|
||||||
if ((float)dayTime / lengthOfDay < 0.5)
|
if ((float)dayTime / lengthOfDay < 0.5)
|
||||||
{
|
{
|
||||||
blue = (int)(((float)nightTime / lengthOfNight) * potatorate) + (int)((1.0f - (float)dayTime / lengthOfDay) * potatorate);
|
blue = (int)(((float)nightTime / lengthOfNight) * 255) + (int)((1.0f - (float)dayTime / lengthOfDay) * 255);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
blue = (int)(((float)nightTime / lengthOfNight) * potatorate) + (int)(((float)dayTime / lengthOfDay) * potatorate);
|
blue = (int)(((float)nightTime / lengthOfNight) * 255) + (int)(((float)dayTime / lengthOfDay) * 255);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((float)nightTime / lengthOfNight < 0.5)
|
if ((float)nightTime / lengthOfNight < 0.5)
|
||||||
{
|
{
|
||||||
red = (int)((1.0 - (float)nightTime / lengthOfNight) * potatorate) + (int)(((float)dayTime / lengthOfDay) * potatorate);
|
red = (int)((1.0 - (float)nightTime / lengthOfNight) * 255) + (int)(((float)dayTime / lengthOfDay) * 255);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
red = (int)(((float)nightTime / lengthOfNight) * potatorate) + (int)(((float)dayTime / lengthOfDay) * potatorate);
|
red = (int)(((float)nightTime / lengthOfNight) * 255) + (int)(((float)dayTime / lengthOfDay) * 255);
|
||||||
}
|
|
||||||
|
|
||||||
if ((float)nightTime / lengthOfNight < 0.5)
|
|
||||||
{
|
|
||||||
green = (int)((1.0 - (float)nightTime / lengthOfNight) * potatorate) + (int)(((float)dayTime / lengthOfDay) * potatorate);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
green = (int)(((float)nightTime / lengthOfNight) * potatorate) + (int)(((float)dayTime / lengthOfDay) * potatorate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Time)
|
if (Time)
|
||||||
@ -130,20 +98,13 @@ class DayNightCycle
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Color.FromNonPremultiplied(red, green, blue, 255);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool nDay()
|
return Color.FromNonPremultiplied(red, 255, blue, brightness);
|
||||||
{
|
|
||||||
if (Time)
|
|
||||||
return true;
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int GetTimeOfDayInt()
|
public int GetTimeOfDayInt()
|
||||||
{
|
{
|
||||||
if (Day)
|
if (Time)
|
||||||
{
|
{
|
||||||
return (int)(100 * ((float)(dayTime + nightTime) / (lengthOfDay + lengthOfNight))) + 1;
|
return (int)(100 * ((float)(dayTime + nightTime) / (lengthOfDay + lengthOfNight))) + 1;
|
||||||
}
|
}
|
||||||
|
@ -1,15 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
|
|
||||||
class Fertilizer
|
|
||||||
{
|
|
||||||
public int ID { get; set; }
|
|
||||||
public string Name { get; set; }
|
|
||||||
public float Nitrogen { get; set; }
|
|
||||||
public float Phosphorus { get; set; }
|
|
||||||
public float Potassium { get; set; }
|
|
||||||
}
|
|
@ -1,181 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
|
|
||||||
class FertilizerHolder
|
|
||||||
{
|
|
||||||
private Fertilizer[] FertilizerType = new Fertilizer[8];
|
|
||||||
|
|
||||||
public void init()
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
FertilizerType[0] = new Fertilizer
|
|
||||||
{
|
|
||||||
ID = 999,
|
|
||||||
Name = "None",
|
|
||||||
Nitrogen = 0.0f / 2,
|
|
||||||
Phosphorus = 0 * 0.436f / 2,
|
|
||||||
Potassium = 0 * 0.83f / 2
|
|
||||||
};
|
|
||||||
|
|
||||||
FertilizerType[1] = new Fertilizer
|
|
||||||
{
|
|
||||||
ID = 0,
|
|
||||||
Name = "10-26-26",
|
|
||||||
Nitrogen = 10.0f / 2,
|
|
||||||
Phosphorus = 26 * 0.436f / 2,
|
|
||||||
Potassium = 26 * 0.83f / 2
|
|
||||||
};
|
|
||||||
|
|
||||||
FertilizerType[2] = new Fertilizer
|
|
||||||
{
|
|
||||||
ID = 1,
|
|
||||||
Name = "14-35-14",
|
|
||||||
Nitrogen = 14.0f / 2,
|
|
||||||
Phosphorus = 35 * 0.436f / 2,
|
|
||||||
Potassium = 14 * 0.83f / 2
|
|
||||||
};
|
|
||||||
|
|
||||||
FertilizerType[3] = new Fertilizer
|
|
||||||
{
|
|
||||||
ID = 2,
|
|
||||||
Name = "17-17-17",
|
|
||||||
Nitrogen = 17.0f / 2,
|
|
||||||
Phosphorus = 17 * 0.436f / 2,
|
|
||||||
Potassium = 17 * 0.83f / 2
|
|
||||||
};
|
|
||||||
|
|
||||||
FertilizerType[4] = new Fertilizer
|
|
||||||
{
|
|
||||||
ID = 3,
|
|
||||||
Name = "20-20",
|
|
||||||
Nitrogen = 20.0f / 2,
|
|
||||||
Phosphorus = 20 * 0.436f / 2,
|
|
||||||
Potassium = 0 * 0.83f / 2
|
|
||||||
};
|
|
||||||
|
|
||||||
FertilizerType[5] = new Fertilizer
|
|
||||||
{
|
|
||||||
ID = 4,
|
|
||||||
Name = "28-28",
|
|
||||||
Nitrogen = 28.0f / 2,
|
|
||||||
Phosphorus = 28 * 0.436f / 2,
|
|
||||||
Potassium = 0 * 0.83f / 2
|
|
||||||
};
|
|
||||||
|
|
||||||
FertilizerType[6] = new Fertilizer
|
|
||||||
{
|
|
||||||
ID = 5,
|
|
||||||
Name = "DAP",
|
|
||||||
Nitrogen = 18.0f / 2,
|
|
||||||
Phosphorus = 46 * 0.436f / 2,
|
|
||||||
Potassium = 0 * 0.83f / 2
|
|
||||||
};
|
|
||||||
|
|
||||||
FertilizerType[7] = new Fertilizer
|
|
||||||
{
|
|
||||||
ID = 6,
|
|
||||||
Name = "Urea",
|
|
||||||
Nitrogen = 46.0f / 2,
|
|
||||||
Phosphorus = 0 * 0.436f / 2,
|
|
||||||
Potassium = 0 * 0.83f / 2
|
|
||||||
};
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
FertilizerType[0] = new Fertilizer
|
|
||||||
{
|
|
||||||
ID = 999,
|
|
||||||
Name = "None",
|
|
||||||
Nitrogen = 0.0f / 2,
|
|
||||||
Phosphorus = 0 * 0.436f / 2,
|
|
||||||
Potassium = 0 * 0.83f / 2
|
|
||||||
};
|
|
||||||
|
|
||||||
FertilizerType[1] = new Fertilizer
|
|
||||||
{
|
|
||||||
ID = 0,
|
|
||||||
Name = "10-26-26",
|
|
||||||
Nitrogen = 17.21f / 2,
|
|
||||||
Phosphorus = 12.14f / 2,
|
|
||||||
Potassium = 0.64f / 2
|
|
||||||
};
|
|
||||||
|
|
||||||
FertilizerType[2] = new Fertilizer
|
|
||||||
{
|
|
||||||
ID = 1,
|
|
||||||
Name = "14-35-14",
|
|
||||||
Nitrogen = 16.89f / 2,
|
|
||||||
Phosphorus = 6.21f / 2,
|
|
||||||
Potassium = 5.21f / 2
|
|
||||||
};
|
|
||||||
|
|
||||||
FertilizerType[3] = new Fertilizer
|
|
||||||
{
|
|
||||||
ID = 2,
|
|
||||||
Name = "17-17-17",
|
|
||||||
Nitrogen = 14.92f / 2,
|
|
||||||
Phosphorus = 14.42f / 2,
|
|
||||||
Potassium = 3.0f / 2
|
|
||||||
};
|
|
||||||
|
|
||||||
FertilizerType[4] = new Fertilizer
|
|
||||||
{
|
|
||||||
ID = 3,
|
|
||||||
Name = "20-20",
|
|
||||||
Nitrogen = 15.39f / 2,
|
|
||||||
Phosphorus = 15.21f / 2,
|
|
||||||
Potassium = 9.5f / 2
|
|
||||||
};
|
|
||||||
|
|
||||||
FertilizerType[5] = new Fertilizer
|
|
||||||
{
|
|
||||||
ID = 4,
|
|
||||||
Name = "28-28",
|
|
||||||
Nitrogen = 9.67f / 2,
|
|
||||||
Phosphorus = 10.47f / 2,
|
|
||||||
Potassium = 9.5f / 2
|
|
||||||
};
|
|
||||||
|
|
||||||
FertilizerType[6] = new Fertilizer
|
|
||||||
{
|
|
||||||
ID = 5,
|
|
||||||
Name = "DAP",
|
|
||||||
Nitrogen = 14.52f / 2,
|
|
||||||
Phosphorus = 1.77f / 2,
|
|
||||||
Potassium = 9.5f / 2
|
|
||||||
};
|
|
||||||
|
|
||||||
FertilizerType[7] = new Fertilizer
|
|
||||||
{
|
|
||||||
ID = 6,
|
|
||||||
Name = "Urea",
|
|
||||||
Nitrogen = 1.81f / 2,
|
|
||||||
Phosphorus = 21.0f / 2,
|
|
||||||
Potassium = 9.5f / 2
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public int GetFertilizerID(string name)
|
|
||||||
{
|
|
||||||
foreach (Fertilizer fertilizer in FertilizerType)
|
|
||||||
{
|
|
||||||
if (fertilizer.Name == name)
|
|
||||||
return fertilizer.ID;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Fertilizer GetFertilizer(string name)
|
|
||||||
{
|
|
||||||
foreach (Fertilizer fertilizer in FertilizerType)
|
|
||||||
{
|
|
||||||
if (fertilizer.Name == name)
|
|
||||||
return fertilizer;
|
|
||||||
}
|
|
||||||
return FertilizerType[0];
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,25 +1,17 @@
|
|||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using System;
|
|
||||||
|
|
||||||
class HandleRotation
|
class HandleRotation
|
||||||
{
|
{
|
||||||
int rotationSpeed = 5, Rotation = 180;
|
int rotationSpeed = 5, Rotation = 180;
|
||||||
private float oldSpeed, movementSpeed;
|
|
||||||
private Vector2 oldTile, oldPosition, oldMovementSpeed;
|
|
||||||
private Vector2 Direction;
|
|
||||||
|
|
||||||
public Vector2 UpdatePosition(int Destination, float tractorSpeed, Vector2 Position, Crops crops, Vector2 oldDeltaPosition, Vector2 Target)
|
public Vector2 UpdatePosition(int Destination, float tractorSpeed, Vector2 Position)
|
||||||
{
|
{
|
||||||
|
Vector2 Direction;
|
||||||
if (oldSpeed != crops.getSpeedFactor(tractorSpeed))
|
if (Destination == 0)
|
||||||
{
|
|
||||||
Position = new Vector2((int)Math.Round(Position.X), (int)Math.Round(Position.Y));
|
|
||||||
}
|
|
||||||
if (Destination == 0) // down
|
|
||||||
{
|
{
|
||||||
if (Rotation == 0)
|
if (Rotation == 0)
|
||||||
{
|
{
|
||||||
Direction = new Vector2(0, 1) * movementSpeed;
|
Direction = new Vector2(0, 1) * tractorSpeed;
|
||||||
Position = Position + Direction;
|
Position = Position + Direction;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -38,11 +30,11 @@ class HandleRotation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (Destination == 1) // up
|
else if (Destination == 1)
|
||||||
{
|
{
|
||||||
if (Rotation == 180)
|
if (Rotation == 180)
|
||||||
{
|
{
|
||||||
Direction = new Vector2(0, -1) * movementSpeed;
|
Direction = new Vector2(0, -1) * tractorSpeed;
|
||||||
Position = Position + Direction;
|
Position = Position + Direction;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -58,11 +50,11 @@ class HandleRotation
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (Destination == 2) // right
|
else if (Destination == 2)
|
||||||
{
|
{
|
||||||
if (Rotation == 270)
|
if (Rotation == 270)
|
||||||
{
|
{
|
||||||
Direction = new Vector2(1, 0) * movementSpeed;
|
Direction = new Vector2(1, 0) * tractorSpeed;
|
||||||
Position = Position + Direction;
|
Position = Position + Direction;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -81,11 +73,11 @@ class HandleRotation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (Destination == 3) // left
|
else if (Destination == 3)
|
||||||
{
|
{
|
||||||
if (Rotation == 90)
|
if (Rotation == 90)
|
||||||
{
|
{
|
||||||
Direction = new Vector2(-1, 0) * movementSpeed;
|
Direction = new Vector2(-1, 0) * tractorSpeed;
|
||||||
Position = Position + Direction;
|
Position = Position + Direction;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -105,12 +97,6 @@ class HandleRotation
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
oldSpeed = crops.getSpeedFactor(tractorSpeed);
|
|
||||||
if (oldDeltaPosition.X < 1 && oldDeltaPosition.X > -1 && oldDeltaPosition.Y < 1 && oldDeltaPosition.Y > -1)
|
|
||||||
{
|
|
||||||
Position = Target;
|
|
||||||
}
|
|
||||||
oldMovementSpeed = Direction;
|
|
||||||
return Position;
|
return Position;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,19 +104,4 @@ class HandleRotation
|
|||||||
{
|
{
|
||||||
return Rotation;
|
return Rotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool checkTile(Vector2 Position, int tileSize, int Spacing, float tractorSpeed, Crops crop)
|
|
||||||
{
|
|
||||||
Vector2 newTile = new Vector2((float)Math.Round(Position.X / (tileSize + Spacing)), (float)Math.Round(Position.Y / (tileSize + Spacing)));
|
|
||||||
if (oldTile != newTile)
|
|
||||||
{
|
|
||||||
oldTile = newTile;
|
|
||||||
movementSpeed = crop.getSpeedFactor(tractorSpeed);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
class Cargo
|
class Cargo
|
||||||
{
|
{
|
||||||
private Items[,] items = new Items[2, 281];
|
private Items[,] items = new Items[2, 30];
|
||||||
private int[] Count = new int[2];
|
private int[] Count = new int[2];
|
||||||
|
|
||||||
|
|
||||||
@ -25,17 +25,17 @@ class Cargo
|
|||||||
items[0, 6] = new Items("Urea", 1, 6);
|
items[0, 6] = new Items("Urea", 1, 6);
|
||||||
|
|
||||||
//Crop Seed Storage
|
//Crop Seed Storage
|
||||||
items[1, 0] = new Items("Barley", 2, 0);
|
items[1, 0] = new Items("Barley", 1, 0);
|
||||||
items[1, 1] = new Items("Cotton", 1, 1);
|
items[1, 1] = new Items("Cotton", 1, 1);
|
||||||
items[1, 2] = new Items("Ground Nuts", 5, 2);
|
items[1, 2] = new Items("Ground Nuts", 1, 2);
|
||||||
items[1, 3] = new Items("Maize", 3, 3);
|
items[1, 3] = new Items("Maize", 1, 3);
|
||||||
items[1, 4] = new Items("Millets", 4, 4);
|
items[1, 4] = new Items("Millets", 1, 4);
|
||||||
items[1, 5] = new Items("Oil Seeds", 4, 5);
|
items[1, 5] = new Items("Oil Seeds", 1, 5);
|
||||||
items[1, 6] = new Items("Paddy", 5, 6);
|
items[1, 6] = new Items("Paddy", 1, 6);
|
||||||
items[1, 7] = new Items("Pulses", 5, 7);
|
items[1, 7] = new Items("Pulses", 1, 7);
|
||||||
items[1, 8] = new Items("Sugarcane", 3, 8);
|
items[1, 8] = new Items("Sugarcane", 1, 8);
|
||||||
items[1, 9] = new Items("Tobacco", 2, 9);
|
items[1, 9] = new Items("Tobacco", 1, 9);
|
||||||
items[1, 10] = new Items("Wheat", 2, 10);
|
items[1, 10] = new Items("Wheat", 1, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addItem(Items item, int Type)
|
public void addItem(Items item, int Type)
|
||||||
|
@ -11,12 +11,9 @@ using Microsoft.Xna.Framework.Input;
|
|||||||
class Inventory
|
class Inventory
|
||||||
{
|
{
|
||||||
private int Weight = 0;
|
private int Weight = 0;
|
||||||
private int maxWeight = 280;
|
private int maxWeight = 25;
|
||||||
private int[] totalHarvested = new int[11];
|
|
||||||
private int[] totalFertilizerUsed = new int[8];
|
|
||||||
private Cargo cargo = new Cargo();
|
private Cargo cargo = new Cargo();
|
||||||
private Cargo itemStorage = new Cargo();
|
private Cargo itemStorage = new Cargo();
|
||||||
private int Refills = 0;
|
|
||||||
|
|
||||||
// Item list by index:
|
// Item list by index:
|
||||||
// ---------------------------------------
|
// ---------------------------------------
|
||||||
@ -62,10 +59,6 @@ class Inventory
|
|||||||
public bool addItem(int newItemIndex, int Type)
|
public bool addItem(int newItemIndex, int Type)
|
||||||
{
|
{
|
||||||
Items newItem;
|
Items newItem;
|
||||||
if (Type == 1)
|
|
||||||
{
|
|
||||||
totalHarvested[newItemIndex]++;
|
|
||||||
}
|
|
||||||
newItem = itemStorage.getItemByIndex(newItemIndex, Type);
|
newItem = itemStorage.getItemByIndex(newItemIndex, Type);
|
||||||
if (maxWeight >= Weight + newItem.getWeight())
|
if (maxWeight >= Weight + newItem.getWeight())
|
||||||
{
|
{
|
||||||
@ -83,14 +76,10 @@ class Inventory
|
|||||||
// Uses an item from the tractor.
|
// Uses an item from the tractor.
|
||||||
// 0 = Fertilizer
|
// 0 = Fertilizer
|
||||||
// 1 = Crops
|
// 1 = Crops
|
||||||
public bool useItem(int Index, int Type, bool isClearing)
|
public bool useItem(int Index, int Type)
|
||||||
{
|
{
|
||||||
if (cargo.itemExists(Index, Type))
|
if (cargo.itemExists(Index, Type))
|
||||||
{
|
{
|
||||||
if (Type == 0 && !isClearing)
|
|
||||||
{
|
|
||||||
totalFertilizerUsed[Index]++;
|
|
||||||
}
|
|
||||||
removeItem(Index, Type);
|
removeItem(Index, Type);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -112,8 +101,6 @@ class Inventory
|
|||||||
|
|
||||||
public void removeItem(int Index, int Type)
|
public void removeItem(int Index, int Type)
|
||||||
{
|
{
|
||||||
|
|
||||||
Weight = Weight - itemStorage.getItemByIndex(Index, Type).getWeight();
|
|
||||||
cargo.removeItem(Index, Type);
|
cargo.removeItem(Index, Type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,102 +109,19 @@ class Inventory
|
|||||||
return itemStorage;
|
return itemStorage;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clearInventory()
|
|
||||||
{
|
|
||||||
for (int i = 0; i <= 6; i++)
|
|
||||||
while (useItem(i, 0, true)) ;
|
|
||||||
|
|
||||||
for (int i = 0; i <= 10; i++)
|
|
||||||
while (useItem(i, 1, true)) ;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void fillWithFertilizer()
|
|
||||||
{
|
|
||||||
Refills++;
|
|
||||||
int fert_amount = 7;
|
|
||||||
float weightPerFertilizer = maxWeight / fert_amount;
|
|
||||||
float min = weightPerFertilizer / 10;
|
|
||||||
float max = (2 * weightPerFertilizer) - min;
|
|
||||||
float expectedUse = Refills * weightPerFertilizer;
|
|
||||||
|
|
||||||
double[] useFactor = new double[fert_amount];
|
|
||||||
for (int i = 0; i < fert_amount; i++)
|
|
||||||
{
|
|
||||||
if (Refills <= 1)
|
|
||||||
useFactor[i] = weightPerFertilizer;
|
|
||||||
else
|
|
||||||
if (totalFertilizerUsed[i] / expectedUse + 0.85f > 1.0f)
|
|
||||||
useFactor[i] = Math.Round(Math.Pow((totalFertilizerUsed[i] / expectedUse) + 0.50f, 0.6f + Math.Min(Refills / 6.0f, 1.0f)) * weightPerFertilizer);
|
|
||||||
else
|
|
||||||
useFactor[i] = Math.Round(Math.Pow((totalFertilizerUsed[i] / expectedUse) + 0.50f, 1.0f + Math.Min(Refills / 6.0f, 1.8f)) * weightPerFertilizer);
|
|
||||||
if (useFactor[i] < min)
|
|
||||||
useFactor[i] = min;
|
|
||||||
else if (useFactor[i] > max)
|
|
||||||
useFactor[i] = max;
|
|
||||||
}
|
|
||||||
int j = 0;
|
|
||||||
bool change = false;
|
|
||||||
while (getWeight() < getMaxWeight() - fert_amount)
|
|
||||||
{
|
|
||||||
if (useFactor[j] > 0)
|
|
||||||
{
|
|
||||||
addItem(j, 0);
|
|
||||||
useFactor[j]--;
|
|
||||||
change = true;
|
|
||||||
}
|
|
||||||
j++;
|
|
||||||
if (j >= fert_amount)
|
|
||||||
{
|
|
||||||
if (!change)
|
|
||||||
break;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
j = 0;
|
|
||||||
change = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int m = 0;
|
|
||||||
while (getWeight() < getMaxWeight()- fert_amount)
|
|
||||||
{
|
|
||||||
if (m > 6)
|
|
||||||
m = 0;
|
|
||||||
addItem(m, 0);
|
|
||||||
m++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool isMissingFertilizer()
|
|
||||||
{
|
|
||||||
for (int i = 0; i <= 6; i++)
|
|
||||||
{
|
|
||||||
if (!itemExists(i, 0))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void printItems(Input input, SpriteBatch spriteBatch, SpriteFont Bold)
|
public void printItems(Input input, SpriteBatch spriteBatch, SpriteFont Bold)
|
||||||
{
|
{
|
||||||
|
|
||||||
spriteBatch.DrawString(Bold, "Crops: ", new Vector2(470, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 2), Color.DarkRed);
|
spriteBatch.DrawString(Bold, "Crops: ", new Vector2(470, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 2), Color.DarkRed);
|
||||||
spriteBatch.DrawString(Bold, "Harvested:", new Vector2(600, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 2), Color.DarkRed);
|
|
||||||
for (int i = 0; i < 11; i++) //Print Crops
|
for (int i = 0; i < 11; i++) //Print Crops
|
||||||
{
|
{
|
||||||
spriteBatch.DrawString(Bold, cargo.getCount(i, 1) + " " + itemStorage.getItemByIndex(i, 1).getItemType(), new Vector2(470, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 20 * i + 22), Color.Teal);
|
spriteBatch.DrawString(Bold, cargo.getCount(i, 1) + " " + itemStorage.getItemByIndex(i, 1).getItemType(), new Vector2(470, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 20 * i + 22), Color.DarkBlue);
|
||||||
spriteBatch.DrawString(Bold, totalHarvested[i].ToString(), new Vector2(620, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 20 * i + 22), Color.Teal);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
spriteBatch.DrawString(Bold, "Fertilizers: ", new Vector2(700, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 2), Color.DarkRed);
|
spriteBatch.DrawString(Bold, "Fertilizers: ", new Vector2(700, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 2), Color.DarkRed);
|
||||||
spriteBatch.DrawString(Bold, "Used ", new Vector2(830, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 2), Color.DarkRed);
|
|
||||||
for (int i = 0; i < 7; i++) //Print Fertilizers
|
for (int i = 0; i < 7; i++) //Print Fertilizers
|
||||||
{
|
{
|
||||||
spriteBatch.DrawString(Bold, cargo.getCount(i, 0) + " " + itemStorage.getItemByIndex(i, 0).getItemType(), new Vector2(700, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 20 * i + 22), Color.Teal);
|
spriteBatch.DrawString(Bold, cargo.getCount(i, 0) + " " + itemStorage.getItemByIndex(i, 0).getItemType(), new Vector2(700, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 20 * i + 22), Color.DarkBlue);
|
||||||
spriteBatch.DrawString(Bold, totalFertilizerUsed[i].ToString(), new Vector2(835, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 20 * i + 22), Color.Teal);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,14 @@
|
|||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
using System;
|
|
||||||
|
|
||||||
class Tractor
|
class Tractor
|
||||||
{
|
{
|
||||||
private int Spacing, sizeTile, Speed = 1;
|
private int Spacing, sizeTile, Speed = 1;
|
||||||
private float tractorSpeed = 1;
|
private float tractorSpeed = 1;
|
||||||
private Vector2 Position, TargetPosition, Size, housePos, DeltaPosition;
|
private Vector2 Position, TargetPosition, Size, housePos;
|
||||||
private Path path = new Path();
|
private Path path = new Path();
|
||||||
private SmartTractor smartTractor = new SmartTractor();
|
private SmartTractor smartTractor = new SmartTractor();
|
||||||
private HandleRotation handleRotation = new HandleRotation();
|
private HandleRotation handleRotation = new HandleRotation();
|
||||||
private int j;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public void updateSizing(Input input, int Status, Vector2 newHousePos, DayNightCycle Time)
|
public void updateSizing(Input input, int Status, Vector2 newHousePos, DayNightCycle Time)
|
||||||
{
|
{
|
||||||
@ -21,7 +17,7 @@ class Tractor
|
|||||||
Size = input.getSize();
|
Size = input.getSize();
|
||||||
updatePosition(input.getSize(), Status);
|
updatePosition(input.getSize(), Status);
|
||||||
housePos = newHousePos;
|
housePos = newHousePos;
|
||||||
smartTractor.UpdateCrops(Speed, Time);
|
smartTractor.UpdateCrops(Speed);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void init(Rectangle house, Input input)
|
public void init(Rectangle house, Input input)
|
||||||
@ -30,14 +26,13 @@ class Tractor
|
|||||||
Spacing = input.getSpacing();
|
Spacing = input.getSpacing();
|
||||||
Position = housePos;
|
Position = housePos;
|
||||||
TargetPosition = new Vector2(house.X, house.Y);
|
TargetPosition = new Vector2(house.X, house.Y);
|
||||||
smartTractor.init(new Vector2(house.X, house.Y));
|
smartTractor.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Runs when the tractor reaches a tile
|
// Runs when the tractor reaches a tile
|
||||||
private void updateDirection(Vector2 Size, Vector2 newPosition)
|
private void updateDirection(Vector2 Size, Vector2 newPosition)
|
||||||
{
|
{
|
||||||
DeltaPosition = TargetPosition - Position;
|
Vector2 DeltaPosition = TargetPosition - Position;
|
||||||
handleRotation.checkTile(Position, sizeTile, Spacing, tractorSpeed, smartTractor.getFarm().getCrop((int)Math.Round(Position.X / (sizeTile + Spacing)), (int)Math.Round(Position.Y / (sizeTile + Spacing))));
|
|
||||||
|
|
||||||
if (DeltaPosition.X == 0)
|
if (DeltaPosition.X == 0)
|
||||||
{
|
{
|
||||||
@ -47,49 +42,30 @@ class Tractor
|
|||||||
}
|
}
|
||||||
else if (DeltaPosition.Y > 0)
|
else if (DeltaPosition.Y > 0)
|
||||||
{
|
{
|
||||||
Position = handleRotation.UpdatePosition(0, tractorSpeed, Position, smartTractor.getFarm().getCrop((int)Math.Round(Position.X / (sizeTile + Spacing)), (int)Math.Round(Position.Y / (sizeTile + Spacing))), DeltaPosition, TargetPosition);
|
Position = handleRotation.UpdatePosition(0, tractorSpeed, Position);
|
||||||
}
|
}
|
||||||
else if (DeltaPosition.Y < 0)
|
else if (DeltaPosition.Y < 0)
|
||||||
{
|
{
|
||||||
Position = handleRotation.UpdatePosition(1, tractorSpeed, Position, smartTractor.getFarm().getCrop((int)Math.Round(Position.X / (sizeTile + Spacing)), (int)Math.Round(Position.Y / (sizeTile + Spacing))), DeltaPosition, TargetPosition);
|
Position = handleRotation.UpdatePosition(1, tractorSpeed, Position);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (DeltaPosition.X > 0)
|
else if (DeltaPosition.X > 0)
|
||||||
{
|
{
|
||||||
Position = handleRotation.UpdatePosition(2, tractorSpeed, Position, smartTractor.getFarm().getCrop((int)Math.Round(Position.X / (sizeTile + Spacing)), (int)Math.Round(Position.Y / (sizeTile + Spacing))), DeltaPosition, TargetPosition);
|
Position = handleRotation.UpdatePosition(2, tractorSpeed, Position);
|
||||||
}
|
}
|
||||||
else if (DeltaPosition.X < 0)
|
else if (DeltaPosition.X < 0)
|
||||||
{
|
{
|
||||||
Position = handleRotation.UpdatePosition(3, tractorSpeed, Position, smartTractor.getFarm().getCrop((int)Math.Round(Position.X / (sizeTile + Spacing)), (int)Math.Round(Position.Y / (sizeTile + Spacing))), DeltaPosition, TargetPosition);
|
Position = handleRotation.UpdatePosition(3, tractorSpeed, Position);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void updatePosition(Vector2 Size, int Status) // updates the position
|
public void updatePosition(Vector2 Size, int Status) // updates the position
|
||||||
{
|
{
|
||||||
|
|
||||||
//farm.updateSize(Size, sizeTile, Spacing);
|
//farm.updateSize(Size, sizeTile, Spacing);
|
||||||
for (int i = 0; i < Speed; i++)
|
for (int i = 0; i < Speed; i++)
|
||||||
{
|
{
|
||||||
|
|
||||||
updateDirection(Size, Position);
|
updateDirection(Size, Position);
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
if (!smartTractor.getWaitTwoFrames())
|
|
||||||
{
|
|
||||||
updateDirection(Size, Position);
|
|
||||||
j = WaitFrame;
|
|
||||||
}
|
|
||||||
else if (j != 0)
|
|
||||||
{
|
|
||||||
j--;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
smartTractor.setWaitTwoFrames(false);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,8 +4,7 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using C5;
|
using Game1.Sources.ML;
|
||||||
using System.Diagnostics;
|
|
||||||
|
|
||||||
class Astar
|
class Astar
|
||||||
{
|
{
|
||||||
@ -14,6 +13,7 @@ class Astar
|
|||||||
private Vector2 housePos;
|
private Vector2 housePos;
|
||||||
private static Crops[,] crops;
|
private static Crops[,] crops;
|
||||||
private Vector2 Size;
|
private Vector2 Size;
|
||||||
|
private PriorityQueue allPaths;
|
||||||
private Vector2 targetPos;
|
private Vector2 targetPos;
|
||||||
private int Rotation;
|
private int Rotation;
|
||||||
|
|
||||||
@ -36,15 +36,20 @@ class Astar
|
|||||||
targetPos = newTargetPos;
|
targetPos = newTargetPos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Nodes getOptimalPath()
|
||||||
|
{
|
||||||
|
return allPaths.Peek();
|
||||||
|
}
|
||||||
|
|
||||||
// Get all adjacent nodes
|
// Get all adjacent nodes
|
||||||
public List<Nodes> GetAdjacentNodes(Vector2 currentPos)
|
public List<Nodes> GetAdjacentNodes(Vector2 currentPos)
|
||||||
{
|
{
|
||||||
var adjacentNodes = new List<Nodes>()
|
var adjacentNodes = new List<Nodes>()
|
||||||
|
|
||||||
{
|
{
|
||||||
new Nodes(new Vector2(currentPos.X, currentPos.Y - 1), 0),
|
new Nodes(new Vector2(currentPos.X, currentPos.Y+1), 0),
|
||||||
new Nodes(new Vector2(currentPos.X + 1, currentPos.Y), 1),
|
new Nodes(new Vector2(currentPos.X + 1, currentPos.Y), 1),
|
||||||
new Nodes(new Vector2(currentPos.X, currentPos.Y + 1), 2),
|
new Nodes(new Vector2(currentPos.X, currentPos.Y - 1), 2),
|
||||||
new Nodes(new Vector2(currentPos.X - 1, currentPos.Y), -1),
|
new Nodes(new Vector2(currentPos.X - 1, currentPos.Y), -1),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -75,7 +80,7 @@ class Astar
|
|||||||
if (currDir == newDir)
|
if (currDir == newDir)
|
||||||
return 0;
|
return 0;
|
||||||
else if (Math.Abs(currDir - newDir) == 1 || Math.Abs(currDir - newDir) == 3)
|
else if (Math.Abs(currDir - newDir) == 1 || Math.Abs(currDir - newDir) == 3)
|
||||||
return 3;
|
return 2;
|
||||||
else if (Math.Abs(currDir - newDir) == 0 || Math.Abs(currDir - newDir) == 2)
|
else if (Math.Abs(currDir - newDir) == 0 || Math.Abs(currDir - newDir) == 2)
|
||||||
return 9;
|
return 9;
|
||||||
return 0;
|
return 0;
|
||||||
@ -85,13 +90,13 @@ class Astar
|
|||||||
public int ConvertRotation()
|
public int ConvertRotation()
|
||||||
{
|
{
|
||||||
int rotation = 0;
|
int rotation = 0;
|
||||||
if (Rotation > 135 && Rotation < 225)
|
if (Rotation == 180)
|
||||||
rotation = 0;
|
rotation = 0;
|
||||||
else if (Rotation > 225 && Rotation < 315)
|
else if (Rotation == 270)
|
||||||
rotation = 1;
|
rotation = 1;
|
||||||
else if (Rotation > 315 && Rotation < 45)
|
else if (Rotation == 0)
|
||||||
rotation = 2;
|
rotation = 2;
|
||||||
else if (Rotation > 45 && Rotation < 135)
|
else if (Rotation == 90)
|
||||||
rotation = -1;
|
rotation = -1;
|
||||||
return rotation;
|
return rotation;
|
||||||
}
|
}
|
||||||
@ -128,6 +133,7 @@ class Astar
|
|||||||
g = current.getG() + crops[(int)adjacentNode.getCords().X, (int)adjacentNode.getCords().Y].getCostOnMovement() + CalculateRotationCost(direction, adjacentNode.getDirection()); // calculate g - cost from start point
|
g = current.getG() + crops[(int)adjacentNode.getCords().X, (int)adjacentNode.getCords().Y].getCostOnMovement() + CalculateRotationCost(direction, adjacentNode.getDirection()); // calculate g - cost from start point
|
||||||
if (!(openList.Exists(adjacentNode.getCords()))) // if adjacent node is not on open list, add it
|
if (!(openList.Exists(adjacentNode.getCords()))) // if adjacent node is not on open list, add it
|
||||||
{
|
{
|
||||||
|
|
||||||
adjacentNode.setG(g);
|
adjacentNode.setG(g);
|
||||||
adjacentNode.setH(ComputeHScore(adjacentNode.getCords(), target.getCords()));
|
adjacentNode.setH(ComputeHScore(adjacentNode.getCords(), target.getCords()));
|
||||||
adjacentNode.calculateF();
|
adjacentNode.calculateF();
|
||||||
@ -159,75 +165,7 @@ class Astar
|
|||||||
|
|
||||||
openList.deleteHeap();
|
openList.deleteHeap();
|
||||||
closedList.deleteHeap();
|
closedList.deleteHeap();
|
||||||
|
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool isReachable(Crops[,] crops, Vector2 targetPos, Vector2 start)
|
|
||||||
{
|
|
||||||
Rotation = 0;
|
|
||||||
int g = 0;
|
|
||||||
int direction = ConvertRotation();
|
|
||||||
Path path = new Path();
|
|
||||||
MinHeap openList = new MinHeap();
|
|
||||||
MinHeap closedList = new MinHeap();
|
|
||||||
Nodes target = new Nodes(targetPos);
|
|
||||||
Nodes startPos = new Nodes(tractorPos, direction);
|
|
||||||
Nodes current = null;
|
|
||||||
|
|
||||||
openList.Insert(startPos);
|
|
||||||
|
|
||||||
while (openList.GetSize() > 0)
|
|
||||||
{
|
|
||||||
current = openList.getMin();
|
|
||||||
closedList.Insert(current);
|
|
||||||
openList.removeMin();
|
|
||||||
direction = current.getDirection();
|
|
||||||
|
|
||||||
if (current.getCords() == target.getCords())
|
|
||||||
break;
|
|
||||||
|
|
||||||
var adjacentNodes = GetAdjacentNodes(current.getCords());
|
|
||||||
foreach (var adjacentNode in adjacentNodes)
|
|
||||||
{
|
|
||||||
if (closedList.Exists(adjacentNode.getCords())) // check if adjacent node is on closed list, if it is, skip it
|
|
||||||
continue;
|
|
||||||
g = current.getG() + crops[(int)adjacentNode.getCords().X, (int)adjacentNode.getCords().Y].getCostOnMovement() + CalculateRotationCost(direction, adjacentNode.getDirection()); // calculate g - cost from start point
|
|
||||||
if (!(openList.Exists(adjacentNode.getCords()))) // if adjacent node is not on open list, add it
|
|
||||||
{
|
|
||||||
adjacentNode.setG(g);
|
|
||||||
adjacentNode.setH(ComputeHScore(adjacentNode.getCords(), target.getCords()));
|
|
||||||
adjacentNode.calculateF();
|
|
||||||
adjacentNode.setParent(current);
|
|
||||||
openList.Insert(adjacentNode);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (g + adjacentNode.getH() < adjacentNode.getF()) // check if adjacent node is a better path than the current one
|
|
||||||
{
|
|
||||||
adjacentNode.setG(g);
|
|
||||||
adjacentNode.calculateF();
|
|
||||||
adjacentNode.setParent(current);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (current != null)
|
|
||||||
{
|
|
||||||
path.AddNode(current);
|
|
||||||
current = current.getParent();
|
|
||||||
}
|
|
||||||
|
|
||||||
openList.deleteHeap();
|
|
||||||
closedList.deleteHeap();
|
|
||||||
|
|
||||||
if (path.getByIndex(0).getCords() != targetPos)
|
|
||||||
return false;
|
|
||||||
else
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
@ -6,9 +6,8 @@ using System.Threading.Tasks;
|
|||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Input;
|
using Microsoft.Xna.Framework.Input;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
using C5;
|
|
||||||
|
|
||||||
class Nodes : IComparable<Nodes>, IEqualityComparer<Nodes>, IPriorityQueueHandle<Nodes>
|
class Nodes
|
||||||
{
|
{
|
||||||
private int F = 0;
|
private int F = 0;
|
||||||
private int G = 0;
|
private int G = 0;
|
||||||
@ -28,12 +27,6 @@ class Nodes : IComparable<Nodes>, IEqualityComparer<Nodes>, IPriorityQueueHandle
|
|||||||
Direction = direction;
|
Direction = direction;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Nodes(int f, Vector2 coordinates)
|
|
||||||
{
|
|
||||||
Coordinates = coordinates;
|
|
||||||
F = f;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Nodes(Nodes node)
|
public Nodes(Nodes node)
|
||||||
{
|
{
|
||||||
F = node.F;
|
F = node.F;
|
||||||
@ -101,24 +94,4 @@ class Nodes : IComparable<Nodes>, IEqualityComparer<Nodes>, IPriorityQueueHandle
|
|||||||
{
|
{
|
||||||
return Direction;
|
return Direction;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int CompareTo(Nodes other)
|
|
||||||
{
|
|
||||||
if (this.F < other.F)
|
|
||||||
return -1;
|
|
||||||
else if (this.F > other.F)
|
|
||||||
return 1;
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Equals(Nodes source, Nodes other)
|
|
||||||
{
|
|
||||||
return (source.Coordinates.X == other.Coordinates.X && source.Coordinates.Y == other.Coordinates.Y);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int GetHashCode(Nodes nodes)
|
|
||||||
{
|
|
||||||
return (nodes.Coordinates.GetHashCode());
|
|
||||||
}
|
|
||||||
}
|
}
|
88
Game1/Sources/Pathing/A-Star/PathSaver/PriorityQueue.cs
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Microsoft.Xna.Framework.Input;
|
||||||
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
|
||||||
|
class PriorityQueue
|
||||||
|
{
|
||||||
|
public List<Nodes> list;
|
||||||
|
public int Count { get { return list.Count; } }
|
||||||
|
|
||||||
|
public PriorityQueue()
|
||||||
|
{
|
||||||
|
list = new List<Nodes>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public PriorityQueue(int count)
|
||||||
|
{
|
||||||
|
list = new List<Nodes>(count);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void Enqueue(Nodes x)
|
||||||
|
{
|
||||||
|
list.Add(x);
|
||||||
|
int i = Count - 1;
|
||||||
|
|
||||||
|
|
||||||
|
while (i > 0)
|
||||||
|
{
|
||||||
|
int p = (i - 1) / 2;
|
||||||
|
if (list[p].getF() <= x.getF()) break;
|
||||||
|
|
||||||
|
list[i] = list[p];
|
||||||
|
i = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Count > 0) list[i] = x;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dequeue()
|
||||||
|
{
|
||||||
|
Nodes min = Peek();
|
||||||
|
Nodes root = list[Count - 1];
|
||||||
|
list.RemoveAt(Count - 1);
|
||||||
|
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
while (i * 2 + 1 < Count)
|
||||||
|
{
|
||||||
|
int a = i * 2 + 1;
|
||||||
|
int b = i * 2 + 2;
|
||||||
|
int c = b < Count && list[b].getF() < list[a].getF() ? b : a;
|
||||||
|
|
||||||
|
if (list[c].getF() >= root.getF()) break;
|
||||||
|
list[i] = list[c];
|
||||||
|
i = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Count > 0) list[i] = root;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public Nodes Peek()
|
||||||
|
{
|
||||||
|
if (Count == 0) throw new InvalidOperationException("Queue is empty.");
|
||||||
|
return list[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean Exists(Vector2 coordinates)
|
||||||
|
{
|
||||||
|
if (Count == 0)
|
||||||
|
return false;
|
||||||
|
foreach(Nodes node in list)
|
||||||
|
{
|
||||||
|
if (node.getCords() == coordinates)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
list.Clear();
|
||||||
|
}
|
||||||
|
}
|
@ -46,9 +46,4 @@ class PriorityQueueC5
|
|||||||
queue.AddAll(entryList);
|
queue.AddAll(entryList);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getCount()
|
|
||||||
{
|
|
||||||
return queue.Count();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
@ -15,10 +15,9 @@ class AI
|
|||||||
private Vector2 Size;
|
private Vector2 Size;
|
||||||
private Vector2 targetPos;
|
private Vector2 targetPos;
|
||||||
private Inventory inventory = new Inventory();
|
private Inventory inventory = new Inventory();
|
||||||
private FertilizerHolder fertilizerHolder = new FertilizerHolder();
|
|
||||||
private int Rotation;
|
private int Rotation;
|
||||||
|
private PriorityQueueC5 PriorityQueueC5;
|
||||||
private Astar astar = new Astar();
|
private Astar astar = new Astar();
|
||||||
public bool WaitTwoFrames { get; set; }
|
|
||||||
|
|
||||||
private Random r = new Random();
|
private Random r = new Random();
|
||||||
|
|
||||||
@ -46,31 +45,14 @@ class AI
|
|||||||
inventory.printItems(input, spriteBatch, Bold);
|
inventory.printItems(input, spriteBatch, Bold);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Path newTarget()
|
|
||||||
|
public Vector2 newTarget()
|
||||||
{
|
{
|
||||||
PriorityQueueC5 queue = new PriorityQueueC5();
|
PriorityQueueC5 queue = new PriorityQueueC5();
|
||||||
int score = 0;
|
int score = 0;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
int testsize = 2;
|
int testsize = 2;
|
||||||
Path newTarget;
|
Vector2 newTarget;
|
||||||
Nodes nodes;
|
|
||||||
Random random = new Random();
|
|
||||||
|
|
||||||
if (astar.GetAdjacentNodes(tractorPos).Count == 0)
|
|
||||||
nodes = new Nodes(housePos);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
List<Nodes> templist = astar.GetAdjacentNodes(tractorPos);
|
|
||||||
nodes = templist[random.Next(0, templist.Count())];
|
|
||||||
templist.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tractorPos != housePos)
|
|
||||||
if (inventory.getWeight() == inventory.getMaxWeight() || inventory.isMissingFertilizer())
|
|
||||||
{
|
|
||||||
astar.update(farm.getCrops(), Size, tractorPos, housePos, housePos, Rotation);
|
|
||||||
return astar.FindPath(true);
|
|
||||||
}
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
for (int x = 0; x < Size.X; x++)
|
for (int x = 0; x < Size.X; x++)
|
||||||
@ -78,57 +60,50 @@ class AI
|
|||||||
{
|
{
|
||||||
if (farm.getCrop(x, y).getStatus() >= 2 && tractorPos != new Vector2(x, y))
|
if (farm.getCrop(x, y).getStatus() >= 2 && tractorPos != new Vector2(x, y))
|
||||||
{
|
{
|
||||||
if (farm.getCrop(x, y).getStatus() != 2 && (farm.getCrop(x, y).getProductionRate() > 0.99f || !farm.getCrop(x, y).belowCapacity()))
|
if (farm.getCrop(x, y).getStatus() == 3 && farm.getCrop(x, y).getCropTimer() != 1)
|
||||||
{
|
{
|
||||||
//skip growing fields with high production rate
|
if (housePos == tractorPos)
|
||||||
|
{
|
||||||
|
score = calculateSoilScore(x, y);
|
||||||
|
queue.AddToQueue(x, y, score);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
//do nothing
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
score = calculateSoilScore(x, y);
|
score = calculateSoilScore(x, y);
|
||||||
queue.AddToQueue(x, y, score);
|
queue.AddToQueue(x, y, score);
|
||||||
if (farm.getCrop(x, y).getCropTimer() == 1 || farm.getCrop(x, y).getStatus() == 2)
|
count++;
|
||||||
count++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (count > 0)
|
||||||
break;
|
break;
|
||||||
|
else if (tractorPos != housePos)
|
||||||
|
return housePos;
|
||||||
|
|
||||||
|
/*
|
||||||
|
else if (tractorPos == housePos)
|
||||||
|
{
|
||||||
|
List<Nodes> temp = astar.GetAdjacentNodes(tractorPos);
|
||||||
|
return temp[0].getCords();
|
||||||
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
if (queue.getCount() == 0)
|
newTarget = GetMinFNode(Math.Min(testsize, count), queue);
|
||||||
{
|
|
||||||
astar.update(farm.getCrops(), Size, tractorPos, housePos, nodes.getCords(), Rotation);
|
|
||||||
return newTarget = astar.FindPath(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
newTarget = GetMinFNode(Math.Min(testsize, queue.getCount()), queue);
|
|
||||||
queue = null;
|
|
||||||
|
|
||||||
return newTarget;
|
return newTarget;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Farm changeCropStatus()
|
public Farm changeCropStatus()
|
||||||
{
|
{
|
||||||
int x = (int)tractorPos.X;
|
if (farm.getCrop((int)tractorPos.X, (int)tractorPos.Y).getCropTimer() == 1)
|
||||||
int y = (int)tractorPos.Y;
|
|
||||||
Fertilizer fertilizer = new Fertilizer();
|
|
||||||
fertilizerHolder.init();
|
|
||||||
WaitTwoFrames = false;
|
|
||||||
if (farm.getCrop(x, y).getStatus() >= 2)
|
|
||||||
{
|
|
||||||
fertilizer = fertilizerHolder.GetFertilizer(Engine.PredictFertilizer(farm.getCrop(x, y), farm.getPresetCropTypes(farm.getCrop(x, y).getCropType())));
|
|
||||||
while (!(farm.getCrop(x, y).isSaturated(-1)) && farm.getCrop(x, y).belowCapacity() && inventory.useItem(fertilizerHolder.GetFertilizerID(fertilizer.Name), 0, false))
|
|
||||||
{
|
|
||||||
farm.getCrop(x, y).Fertilize(fertilizer);
|
|
||||||
fertilizer = fertilizerHolder.GetFertilizer(Engine.PredictFertilizer(farm.getCrop(x, y), farm.getPresetCropTypes(farm.getCrop(x, y).getCropType())));
|
|
||||||
WaitTwoFrames = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (farm.getCrop(x, y).getCropTimer() == 1)
|
|
||||||
{
|
{
|
||||||
farm.setCropStatus(tractorPos.X, tractorPos.Y);
|
farm.setCropStatus(tractorPos.X, tractorPos.Y);
|
||||||
if (farm.getCrop(x, y).getStatus() == 2)
|
if (farm.getCrop((int)tractorPos.X, (int)tractorPos.Y).getStatus() == 2)
|
||||||
{
|
{
|
||||||
inventory.addItem(farm.getCrop(x, y).getCropType() - 1, 1);
|
inventory.addItem(farm.getCrop((int)tractorPos.X, (int)tractorPos.Y).getCropType() - 1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -142,38 +117,50 @@ class AI
|
|||||||
|
|
||||||
private int calculateSoilScore(int x, int y)
|
private int calculateSoilScore(int x, int y)
|
||||||
{
|
{
|
||||||
int score = 1;
|
int score = 0;
|
||||||
int statusScore = 1;
|
int statusScore = 0;
|
||||||
int timerScore = 1;
|
|
||||||
int saturationScore = 1;
|
|
||||||
int productionRateScore = 1;
|
|
||||||
int aproxDistance = (int)(Math.Abs(x - tractorPos.X) + Math.Abs(y - tractorPos.Y));
|
int aproxDistance = (int)(Math.Abs(x - tractorPos.X) + Math.Abs(y - tractorPos.Y));
|
||||||
|
CropTypesHolder holder = new CropTypesHolder();
|
||||||
|
holder.init();
|
||||||
|
|
||||||
Crops crop = farm.getCrop(x, y);
|
Crops crop = farm.getCrop(x, y);
|
||||||
|
SoilProperties soilP = crop.getSoilProperties();
|
||||||
int cropType = crop.getCropType();
|
int cropType = crop.getCropType();
|
||||||
|
CropTypes avgHold = holder.getPresetCropTypes(cropType);
|
||||||
if (crop.getCropTimer() == 1)
|
|
||||||
timerScore = 100;
|
|
||||||
|
|
||||||
productionRateScore = (int)(crop.getProductionRate() * 25);
|
|
||||||
score = (int)(crop.getProductionRate() * -50);
|
|
||||||
|
|
||||||
if (crop.getStatus() == 2)
|
if (crop.getStatus() == 2)
|
||||||
{
|
statusScore = 25;
|
||||||
statusScore = 50;
|
|
||||||
productionRateScore = 0;
|
|
||||||
}
|
|
||||||
else if (crop.getStatus() == 3)
|
else if (crop.getStatus() == 3)
|
||||||
statusScore = -100;
|
statusScore = 5;
|
||||||
|
else if (crop.getStatus() == 4)
|
||||||
if (!crop.isSaturated(2))
|
statusScore = -10;
|
||||||
saturationScore = 5;
|
|
||||||
else
|
else
|
||||||
|
statusScore = 1;
|
||||||
|
|
||||||
|
float[] currentValue = { soilP.Temperature, soilP.Humidity, soilP.Moisture, soilP.Nitrogen, soilP.Potassium, soilP.Phosphorous };
|
||||||
|
float[] targetAvg = { avgHold.Temparature, avgHold.Humidity, avgHold.Moisture, avgHold.Nitrogen, avgHold.Potassium, avgHold.Phosphorous };
|
||||||
|
float[,] minMax = { {22,30}, {22*1.9f, 30*2.1f}, {20, 70}, {4, 55}, {0, 28}, {0, 60} }; //probably should make it dynamic
|
||||||
|
float[] normVal = normArray(minMax, currentValue);
|
||||||
|
float[] normAvg = normArray(minMax, targetAvg);
|
||||||
|
|
||||||
|
for (int i = 0; i < normVal.Count(); i++)
|
||||||
{
|
{
|
||||||
saturationScore = -100;
|
score = score + (int)Math.Round(System.Convert.ToDouble(10*(1 - Math.Abs(normAvg[i] - normVal[i]))));
|
||||||
}
|
}
|
||||||
|
|
||||||
return score + (-aproxDistance * 10) + statusScore + timerScore + saturationScore;
|
return score + (-aproxDistance * 3) + statusScore;
|
||||||
|
}
|
||||||
|
|
||||||
|
private float[] normArray(float[,] minMax, float[] values)
|
||||||
|
{
|
||||||
|
float[] temp = new float[values.Count()];
|
||||||
|
if (minMax.GetLength(0) != values.Count())
|
||||||
|
throw new InvalidOperationException("Values and their MinMax arrays are not of the same length!");
|
||||||
|
|
||||||
|
for (int i = 0; i < values.Count(); i++)
|
||||||
|
temp[i] = norm(minMax[i, 0], minMax[i, 1], values[i]);
|
||||||
|
|
||||||
|
return temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
private float norm(float min, float max, float val)
|
private float norm(float min, float max, float val)
|
||||||
@ -181,13 +168,12 @@ class AI
|
|||||||
return ((val - min) / (max - min));
|
return ((val - min) / (max - min));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Path GetMinFNode(int testSize, PriorityQueueC5 queue)
|
public Vector2 GetMinFNode(int testSize, PriorityQueueC5 queue)
|
||||||
{
|
{
|
||||||
int index = 0;
|
int index = 0;
|
||||||
int min = 9999;
|
int min = 999;
|
||||||
Path path = new Path();
|
Path path = new Path();
|
||||||
List<PQEntry> entryList = new List<PQEntry>();
|
List<PQEntry> entryList = new List<PQEntry>();
|
||||||
Path[] pathList = new Path[testSize];
|
|
||||||
for (int i = 0; i < testSize; i++)
|
for (int i = 0; i < testSize; i++)
|
||||||
{
|
{
|
||||||
entryList.Add(queue.DeleteMax());
|
entryList.Add(queue.DeleteMax());
|
||||||
@ -196,9 +182,7 @@ class AI
|
|||||||
for (int i = 0; i < testSize; i++)
|
for (int i = 0; i < testSize; i++)
|
||||||
{
|
{
|
||||||
Nodes temp = new Nodes(entryList[i].Coordinates);
|
Nodes temp = new Nodes(entryList[i].Coordinates);
|
||||||
astar.update(farm.getCrops(), Size, tractorPos, housePos, temp.getCords(), Rotation);
|
|
||||||
path = astar.FindPath(false);
|
path = astar.FindPath(false);
|
||||||
pathList[i] = path;
|
|
||||||
Nodes tempF = new Nodes(path.getByIndex(0));
|
Nodes tempF = new Nodes(path.getByIndex(0));
|
||||||
if (min > tempF.getF())
|
if (min > tempF.getF())
|
||||||
{
|
{
|
||||||
@ -206,47 +190,13 @@ class AI
|
|||||||
index = i;
|
index = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
PQEntry minEntry = entryList[index];
|
||||||
|
entryList.RemoveAt(index);
|
||||||
|
|
||||||
return pathList[index].FlipArray();
|
//add the non-minimum entries back to the queue.
|
||||||
|
queue.AddAll(entryList);
|
||||||
|
|
||||||
|
return minEntry.Coordinates;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Path GetMaxFNode(int testSize, PriorityQueueC5 queue)
|
|
||||||
{
|
|
||||||
int index = 0;
|
|
||||||
int max = -9999;
|
|
||||||
Path path = new Path();
|
|
||||||
List<PQEntry> entryList = new List<PQEntry>();
|
|
||||||
Path[] pathList = new Path[testSize];
|
|
||||||
for (int i = 0; i < testSize; i++)
|
|
||||||
{
|
|
||||||
entryList.Add(queue.DeleteMax());
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < testSize; i++)
|
|
||||||
{
|
|
||||||
Nodes temp = new Nodes(entryList[i].Coordinates);
|
|
||||||
astar.update(farm.getCrops(), Size, tractorPos, housePos, temp.getCords(), Rotation);
|
|
||||||
path = astar.FindPath(false);
|
|
||||||
pathList[i] = path;
|
|
||||||
Nodes tempF = new Nodes(path.getByIndex(0));
|
|
||||||
if (max < tempF.getF())
|
|
||||||
{
|
|
||||||
max = tempF.getF();
|
|
||||||
index = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return pathList[index].FlipArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void reloadCargo()
|
|
||||||
{
|
|
||||||
inventory.clearInventory();
|
|
||||||
inventory.fillWithFertilizer();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -16,18 +16,14 @@ class SmartTractor
|
|||||||
//What to do next
|
//What to do next
|
||||||
public Path returnChoice()
|
public Path returnChoice()
|
||||||
{
|
{
|
||||||
//System.Threading.ThreadStart tractorThread = new System.Threading.ThreadStart(farm.UpdatePreferedCrops);
|
|
||||||
ai.update(farm, Size, tractorPos / (tileSize + Spacing), housePos / (tileSize + Spacing), Target / (tileSize + Spacing), Rotation);
|
ai.update(farm, Size, tractorPos / (tileSize + Spacing), housePos / (tileSize + Spacing), Target / (tileSize + Spacing), Rotation);
|
||||||
//farm.UpdatePreferedCrops(Size);
|
farm.UpdatePreferedCrops(Size);
|
||||||
farm = ai.changeCropStatus();
|
farm = ai.changeCropStatus();
|
||||||
astar.update(farm.getCrops(), Size, tractorPos / (tileSize + Spacing), housePos / (tileSize + Spacing), Rotation);
|
astar.update(farm.getCrops(), Size, tractorPos / (tileSize + Spacing), housePos / (tileSize + Spacing), Rotation);
|
||||||
//getTargetPosition(ai.newTarget());
|
getTargetPosition(ai.newTarget());
|
||||||
//astar.update(farm.getCrops(), Size, tractorPos / (tileSize + Spacing), housePos / (tileSize + Spacing), Target / (tileSize + Spacing), Rotation);
|
astar.update(farm.getCrops(), Size, tractorPos / (tileSize + Spacing), housePos / (tileSize + Spacing), Target / (tileSize + Spacing), Rotation);
|
||||||
if (tractorPos == housePos)
|
|
||||||
ai.reloadCargo();
|
|
||||||
|
|
||||||
return ai.newTarget();
|
return astar.FindPath(true);
|
||||||
//return astar.FindPath(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -44,14 +40,13 @@ class SmartTractor
|
|||||||
tileSize = newTileSize;
|
tileSize = newTileSize;
|
||||||
Spacing = newSpacing;
|
Spacing = newSpacing;
|
||||||
Rotation = rotation;
|
Rotation = rotation;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void init(Vector2 nHousePos)
|
public void init()
|
||||||
{
|
{
|
||||||
ai.init();
|
ai.init();
|
||||||
housePos = nHousePos;
|
|
||||||
farm.init(new Vector2(100, (GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Height / tileSize) - 125 / tileSize), housePos / (tileSize + Spacing));
|
farm.init(new Vector2(100, (GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Height / tileSize) - 125 / tileSize), housePos / (tileSize + Spacing));
|
||||||
farm.UpdatePreferedCrops(Size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void drawInventory(Input input, SpriteBatch spriteBatch, SpriteFont Bold, Cargo itemStorageDefined)
|
public void drawInventory(Input input, SpriteBatch spriteBatch, SpriteFont Bold, Cargo itemStorageDefined)
|
||||||
@ -74,27 +69,16 @@ class SmartTractor
|
|||||||
farm.setNewHousePos(pos, newState);
|
farm.setNewHousePos(pos, newState);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateCrops(int Speed, DayNightCycle nTime)
|
public void UpdateCrops(int Speed)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < Speed; i++)
|
for (int i = 0; i < Speed; i++)
|
||||||
{
|
{
|
||||||
farm.updateFarm(Size);
|
farm.updateFarm(Size);
|
||||||
}
|
}
|
||||||
farm.updateRainFall(Size, nTime);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Inventory getInventory()
|
public Inventory getInventory()
|
||||||
{
|
{
|
||||||
return ai.getInventory();
|
return ai.getInventory();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool getWaitTwoFrames()
|
|
||||||
{
|
|
||||||
return ai.WaitTwoFrames;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setWaitTwoFrames(bool input)
|
|
||||||
{
|
|
||||||
ai.WaitTwoFrames = input;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,103 +0,0 @@
|
|||||||
Machine Learning Implementation
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
|
|
||||||
|
|
||||||
I have implemented a ML to add in season, daily rainfall and area which can be cultivated into the Productivity rate of each crop. This dataset contains over 65000 entries of which we only use around 20000 as those are the only crops that are plantable for our agen and the lowest amount of entries for a single crop is 600. The daily rainfall has been added to SoilProperties in our tileset. Implementation of the needed properties into SoilProperties:
|
|
||||||
|
|
||||||
|
|
||||||
public float Rainfall;
|
|
||||||
public float prevRainfall;
|
|
||||||
public int Area;
|
|
||||||
|
|
||||||
|
|
||||||
.
|
|
||||||
.
|
|
||||||
.
|
|
||||||
|
|
||||||
|
|
||||||
//Randomize the first days rainfall and the area,
|
|
||||||
prevRainfall = r.Next(247, 3617);
|
|
||||||
Area = r.Next(1, 270000);
|
|
||||||
|
|
||||||
|
|
||||||
The dataset is said to be based on real life data. But for our our program is not able to fit the data 1 to 1 because some Crops only had an daily rainfall from 247 to 2000 but the Rainfall of that tile could still be 3617. I haven’t done anything to mitigate this but it doesn’t result in any strange results when passing through our data into the ML Model. It would have been better for the dataset contained rainfall data from 247 to 3617. Then the yield could possibly be lower or higher as rainfall increases or decreases. We added dynamic rainfall in is therefore constricting the rain from going outside of the datasets parameters:
|
|
||||||
|
|
||||||
|
|
||||||
//Sets previous days rainfall to current days rainfall and constrict the total rainfall from going outside of the parameters
|
|
||||||
soilProperties.prevRainfall = soilProperties.Rainfall;
|
|
||||||
if (soilProperties.prevRainfall > 3616)
|
|
||||||
soilProperties.prevRainfall = 3616;
|
|
||||||
else if (soilProperties.prevRainfall < 236)
|
|
||||||
soilProperties.prevRainfall = 236;
|
|
||||||
soilProperties.Rainfall = 0;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Implementation
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
I have used gradient boosting decision tree algorithm due to the features.
|
|
||||||
I used Gradient Boosting Decision Tree Algorithm for this task due to many features it has.
|
|
||||||
First a csv file is loaded:
|
|
||||||
IDataView trainingDataView = mlContext.Data.LoadFromTextFile<ModelInput>(
|
|
||||||
path: path,
|
|
||||||
hasHeader: true,
|
|
||||||
separatorChar: ',',
|
|
||||||
allowQuoting: true,
|
|
||||||
allowSparse: false);
|
|
||||||
Then it is passed to next function which will train, evaluate and build a model:
|
|
||||||
- maximizing number of leaves,
|
|
||||||
- limiting maximum tree depth,
|
|
||||||
- maximizing the amount of bins per feature,
|
|
||||||
|
|
||||||
|
|
||||||
maintaining high accuracy by:
|
|
||||||
- low learning rate combine with:
|
|
||||||
- high number of iterations.
|
|
||||||
|
|
||||||
|
|
||||||
Creating pipeline for the model:
|
|
||||||
var pipeline = mlContext.Transforms
|
|
||||||
.Text.FeaturizeText("SeasonF", "Season")
|
|
||||||
.Append(mlContext.Transforms.Text.FeaturizeText("CropF", "Crop"))
|
|
||||||
.Append(mlContext.Transforms.Concatenate("Features", "SeasonF", "CropF", "Area", "Rainfall"))
|
|
||||||
.AppendCacheCheckpoint(mLContext)
|
|
||||||
.Append(mLContext.Regression.Trainers.LightGbm(options));
|
|
||||||
|
|
||||||
|
|
||||||
.Append(mlContext.Transforms.Conversion.MapKeyToValue("PredictedLabel", "PredictedLabel"));
|
|
||||||
|
|
||||||
|
|
||||||
Integration
|
|
||||||
|
|
||||||
|
|
||||||
Our tileset now has a dynamically moving overlay of clouds moving at the speed of WindSpeed and if the clouds are above at a tile we add to the total rainfall of the day. The rainfall we pass into the ML Model is the previous days rainfall and the first days rainfall is randomized.
|
|
||||||
|
|
||||||
|
|
||||||
We achieved this rainsystem by running a bitmap over our tileset, the bitmap is continues with itself so it runs seamlessly. Depending on the ransparency of each pixel on this bitmap we determine how much it is currently raining on set tile:
|
|
||||||
|
|
||||||
|
|
||||||
if (Rain >= 0.45f)
|
|
||||||
{
|
|
||||||
soilProperties.Rainfall = soilProperties.Rainfall + Rain * 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if the transparency is < 0.45 then there will be no cloud drawn and it will not be raining at all. And this is the result:
|
|
||||||
|
|
||||||
|
|
||||||
(https://git.wmi.amu.edu.pl/s425077/PotatoPlan/raw/Oskar-ML/Example.jpg)
|
|
||||||
|
|
||||||
|
|
||||||
To optimize the program we now update 10% of the columns every second or else it would freeze for seconds at a time and the ML Model is only being fed data once a day as the total rainfall is only updated once a day anyways.
|
|
@ -1,120 +0,0 @@
|
|||||||
# Machine Learning implementation report
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Introduction
|
|
||||||
|
|
||||||
Purpose of my ML implementation is for the agent (tractor) to decide what fertilizer it should use.
|
|
||||||
It's decision is mostly based on nutrients in soil, but also on few other properties.
|
|
||||||
Dataset is very small, it contains only 100 entries.
|
|
||||||
There are 7 types of fertilizers, each of them adding a specific amount of nutrients to the soil.
|
|
||||||
Example:
|
|
||||||
|
|
||||||
FertilizerType[6] = new Fertilizer
|
|
||||||
{
|
|
||||||
ID = 5,
|
|
||||||
Name = "DAP",
|
|
||||||
Nitrogen = 14.52f / 5,
|
|
||||||
Phosphorus = 1.77f / 5,
|
|
||||||
Potassium = 9.5f / 5
|
|
||||||
};
|
|
||||||
|
|
||||||
Unfortunately values of nutrients are not based on real values.
|
|
||||||
That is because even though dataset intention (by it's creator) was to be used to classify fertilizers, it looks like instead it says what fertilizer WAS used and what will be the results of using that fertilizer on some field.
|
|
||||||
E.g: Urea has 46% of Nitrogen in it and nothing else. In dataset it was classified as best fertilizer to be used on fields with already really high Nitrogen levels. That would lead to oversaturation with Nitrogen and lack of other nutrients.
|
|
||||||
So i did some calculations and Urea now looks like this:
|
|
||||||
|
|
||||||
FertilizerType[7] = new Fertilizer
|
|
||||||
{
|
|
||||||
ID = 6,
|
|
||||||
Name = "Urea",
|
|
||||||
Nitrogen = 1.81f / 5,
|
|
||||||
Phosphorus = 21.0f / 5,
|
|
||||||
Potassium = 9.5f / 5
|
|
||||||
};
|
|
||||||
// an "inversed" and little modified counterpart of real-world version of this fertilizer.
|
|
||||||
|
|
||||||
|
|
||||||
## Implementation
|
|
||||||
|
|
||||||
I used Gradient Boosting Decision Tree Algorithm for this task due to many features it has.
|
|
||||||
|
|
||||||
First a csv file is loaded:
|
|
||||||
|
|
||||||
IDataView trainingDataView = mlContext.Data.LoadFromTextFile<ModelInput>(
|
|
||||||
path: path,
|
|
||||||
hasHeader: true,
|
|
||||||
separatorChar: ',',
|
|
||||||
allowQuoting: true,
|
|
||||||
allowSparse: false);
|
|
||||||
|
|
||||||
Then it is passed to next function which will train, evaluate and build a model.
|
|
||||||
Also trainer parameters will be fine-tuned here to prevent overfitting as much as possible by:
|
|
||||||
- limiting number of leaves,
|
|
||||||
- limiting maximum tree depth,
|
|
||||||
- limiting the amount of bins per feature,
|
|
||||||
while maintaining high accuracy by:
|
|
||||||
- low learning rate combine with
|
|
||||||
- high number of iterations.
|
|
||||||
|
|
||||||
var options = new LightGbmMulticlassTrainer.Options
|
|
||||||
{
|
|
||||||
MaximumBinCountPerFeature = 8,
|
|
||||||
LearningRate = 0.00025,
|
|
||||||
NumberOfIterations = 40000,
|
|
||||||
NumberOfLeaves = 10,
|
|
||||||
LabelColumnName = "Fertilizer_NameF",
|
|
||||||
FeatureColumnName = "Features",
|
|
||||||
|
|
||||||
Booster = new DartBooster.Options()
|
|
||||||
{
|
|
||||||
MaximumTreeDepth = 10
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Creating pipeline for the model:
|
|
||||||
|
|
||||||
var pipeline = mlContext.Transforms
|
|
||||||
.Text.FeaturizeText("Soil_TypeF", "Soil_Type")
|
|
||||||
.Append(mlContext.Transforms.Text.FeaturizeText("Crop_TypeF", "Crop_Type"))
|
|
||||||
.Append(mlContext.Transforms.Concatenate("Features", "Temperature", "Humidity", "Moisture", "Soil_TypeF", "Crop_TypeF", "Nitrogen", "Potassium", "Phosphorous"))
|
|
||||||
.Append(mlContext.Transforms.Conversion.MapValueToKey("Fertilizer_NameF", "Fertilizer_Name"), TransformerScope.TrainTest)
|
|
||||||
.AppendCacheCheckpoint(mLContext)
|
|
||||||
.Append(mLContext.MulticlassClassification.Trainers.LightGbm(options))
|
|
||||||
.Append(mlContext.Transforms.Conversion.MapKeyToValue("PredictedLabel", "PredictedLabel"));
|
|
||||||
|
|
||||||
Evaluation of the pipeline is done with cross-validation method with 10 folds.
|
|
||||||
Results are as follow:
|
|
||||||
|
|
||||||
Micro Accuracy: 0.95829
|
|
||||||
LogLoss Average: 0.100171
|
|
||||||
LogLoss Reduction: 0.933795
|
|
||||||
|
|
||||||
Model is created and saved for later use, to skip long trainig and evaluation times.
|
|
||||||
Later that model is loaded and prediction engine is created when program is started.
|
|
||||||
|
|
||||||
|
|
||||||
## Integration Details
|
|
||||||
|
|
||||||
Agent (tractor) navigates trough the grid looking for tiles where it can plant some plants.
|
|
||||||
Upon planting and visitin already growing plants agent decides if any fertilizer is needed (rule based decision), and what fertilizer to use (using ML prediction engine).
|
|
||||||
|
|
||||||
if (farm.getCrop(x, y).getStatus() >= 2)
|
|
||||||
{
|
|
||||||
fertilizer = fertilizerHolder.GetFertilizer(Engine.PredictFertilizer(farm.getCrop(x, y), farm.getPresetCropTypes(farm.getCrop(x, y).getCropType())));
|
|
||||||
while (!(farm.getCrop(x, y).isSaturated(-1)) && farm.getCrop(x, y).belowCapacity() && inventory.useItem(fertilizerHolder.GetFertilizerID(fertilizer.Name), 0))
|
|
||||||
{
|
|
||||||
farm.getCrop(x, y).Fertilize(fertilizer);
|
|
||||||
fertilizer = fertilizerHolder.GetFertilizer(Engine.PredictFertilizer(farm.getCrop(x, y), farm.getPresetCropTypes(farm.getCrop(x, y).getCropType())));
|
|
||||||
WaitTwoFrames = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
If field is properly fertilized it will have higher production rate, resulting in faster growth of a plant.
|
|
||||||
Production rate value is shown in the UI as well as it is represented by the colour of progression bar (right side of every tile).
|
|
||||||
At 100% bar will pure **Green**. Any value below will make bar more **Red**, while any value above will add **Blue**, eventually turning bar colour into cyan.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
|
|
||||||
![Progression Bar](https://git.wmi.amu.edu.pl/s425077/PotatoPlan/raw/Oskar-ML/example_img.jpg)
|
|
||||||
|
|
BIN
example_img.jpg
Before Width: | Height: | Size: 11 KiB |