<commit_before>package com.veil.ai;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;

import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.math.Vector2;
import com.veil.game.GameConstant;
import com.veil.game.element.DynamicEntity;

public class RangeProfile {
	
	public class DistanceLog implements Serializable {
		private static final long serialVersionUID = 8048529594171440656L;
		
		private int speed;
		private List<Integer> list;
		private List<Boolean> miss;
		
		public DistanceLog(int speed){
			this.speed = speed;
			list = new ArrayList<Integer>();
			miss = new ArrayList<Boolean>();
		}
		
		public void add(int distance, boolean playerDamaged){
			list.add(distance);
			miss.add(playerDamaged);
		}
		
		public int sum(){
			int sum = 0;
			for(int i=0; i<list.size(); i++){
				if(!miss.get(i))
					sum += list.get(i);
			}
			return sum;
		}
		
		public int sampleSize(){
			int validSize = 0;
			for(int i=0; i<list.size(); i++){
				if(!miss.get(i))
					validSize++;
			}
			return validSize;
		}
		
		public float average(){
			if(list.size() == 0) return 0;
			int size = sampleSize();
			if(size == 0) return 0;
			return 1f*sum()/size;
		}
		
		@Override
		public String toString(){
			StringBuilder strb = new StringBuilder();
			strb.append(speed).append(" :");
			for(int i=0; i<list.size(); i++){
				strb.append(" ");
				if(miss.get(i)){
					strb.append("-");
				}
				strb.append(list.get(i));
			}
			return strb.toString();
		}
		
		private void writeObject(java.io.ObjectOutputStream out) throws IOException {
			out.writeInt(speed);
			out.writeInt(list.size());
			for(int data : list){
				out.writeInt(data);
			}
			out.writeInt(miss.size());
			for(boolean data : miss){
				out.writeBoolean(data);
			}
		}
		
		private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
			speed = in.readInt();
			int listSize = in.readInt();
			list = new ArrayList<Integer>(listSize);
			for(int i=0; i<listSize; i++){
				list.add(in.readInt());
			}
			listSize = in.readInt();
			miss = new ArrayList<Boolean>(listSize);
			for(int i=0; i<listSize; i++){
				miss.add(in.readBoolean());
			}
		}

		@SuppressWarnings("unused")
		private void readObjectNoData() throws ObjectStreamException {
			this.speed = -1;
			list = new LinkedList<Integer>();
		}
	}
	
	public static RangeProfile instance = new RangeProfile(GameConstant.profileDir.child("Screenshot_range"));
	
	private HashMap<Integer, DistanceLog> logs = new HashMap<Integer, DistanceLog>();
	private boolean sessionLogged = false;
	private int pendingSpeed, pendingDistance;
	private boolean playerDamaged, bulletPassPlayer;
	
	private FileHandle ssDir;
	private int ssFilename;
	
	public RangeProfile(){
		this(null);
	}
	
	public RangeProfile(FileHandle fh){
		reset(null);
		ssDir = fh;
		if(ssDir != null){
			ssFilename = ssDir.list().length;
		}
	}
	
	/**
	 * Save previous profile (if available) to target directory and reset
	 */
	public void reset(FileHandle fh){
		if(fh != null && logs.size() > 0){
			save(fh.child("range_profile.txt"));
		}
		pendingSpeed = -1;
		pendingDistance = -1;
		playerDamaged = false;
		bulletPassPlayer = false;
		sessionLogged = false;
		logs.clear();
	}
	
	public void preUpdate(LevelSnapshot snapshot){
		if(snapshot.playerState.jumping && !sessionLogged){
			String iden = snapshot.enemy.identifier;
			pendingSpeed = Integer.parseInt(iden.substring(iden.lastIndexOf("_")+1));
			if(snapshot.tempRect.size() > 0){
				Vector2 firstAttackPos = new Vector2();
				snapshot.tempRect.values().iterator().next().getCenter(firstAttackPos);
				Vector2 playerPos = new Vector2();
				snapshot.playerRect.getCenter(playerPos);
				pendingDistance = (int)firstAttackPos.dst(playerPos);
			}
			if(ssDir != null){
				ScreenshotUtility.takeScreenshot(ssDir, ""+ssFilename);
				ssFilename++;
			}
			sessionLogged = true;
		}
		if(snapshot.player.getBaseHP() < snapshot.player.maxhp){
			playerDamaged = true;
		}
		for(DynamicEntity dyn : snapshot.tempRect.keySet()){
			if(dyn.getWorldCollider().x < snapshot.player.getWorldCollider().x){
				bulletPassPlayer = true;
			}
		}
	}
	
	/**
	 * Call when current range profiling session should end. Return true if the player is damaged during the session
	 * OR the session ends prematurely (end before enemy's first shoot)
	 */<commit_msg>Add session end check, increase bulletPassPlayer threshold<commit_after>package com.veil.ai;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;

import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.math.Vector2;
import com.veil.game.GameConstant;
import com.veil.game.element.DynamicEntity;

public class RangeProfile {
	
	public class DistanceLog implements Serializable {
		private static final long serialVersionUID = 8048529594171440656L;
		
		private int speed;
		private List<Integer> list;
		private List<Boolean> miss;
		
		public DistanceLog(int speed){
			this.speed = speed;
			list = new ArrayList<Integer>();
			miss = new ArrayList<Boolean>();
		}
		
		public void add(int distance, boolean playerDamaged){
			list.add(distance);
			miss.add(playerDamaged);
		}
		
		public int sum(){
			int sum = 0;
			for(int i=0; i<list.size(); i++){
				if(!miss.get(i))
					sum += list.get(i);
			}
			return sum;
		}
		
		public int sampleSize(){
			int validSize = 0;
			for(int i=0; i<list.size(); i++){
				if(!miss.get(i))
					validSize++;
			}
			return validSize;
		}
		
		public float average(){
			if(list.size() == 0) return 0;
			int size = sampleSize();
			if(size == 0) return 0;
			return 1f*sum()/size;
		}
		
		@Override
		public String toString(){
			StringBuilder strb = new StringBuilder();
			strb.append(speed).append(" :");
			for(int i=0; i<list.size(); i++){
				strb.append(" ");
				if(miss.get(i)){
					strb.append("-");
				}
				strb.append(list.get(i));
			}
			return strb.toString();
		}
		
		private void writeObject(java.io.ObjectOutputStream out) throws IOException {
			out.writeInt(speed);
			out.writeInt(list.size());
			for(int data : list){
				out.writeInt(data);
			}
			out.writeInt(miss.size());
			for(boolean data : miss){
				out.writeBoolean(data);
			}
		}
		
		private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
			speed = in.readInt();
			int listSize = in.readInt();
			list = new ArrayList<Integer>(listSize);
			for(int i=0; i<listSize; i++){
				list.add(in.readInt());
			}
			listSize = in.readInt();
			miss = new ArrayList<Boolean>(listSize);
			for(int i=0; i<listSize; i++){
				miss.add(in.readBoolean());
			}
		}

		@SuppressWarnings("unused")
		private void readObjectNoData() throws ObjectStreamException {
			this.speed = -1;
			list = new LinkedList<Integer>();
		}
	}
	
	public static RangeProfile instance = new RangeProfile(GameConstant.profileDir.child("Screenshot_range"));
	
	private HashMap<Integer, DistanceLog> logs = new HashMap<Integer, DistanceLog>();
	private boolean sessionLogged = false;
	private int pendingSpeed, pendingDistance;
	private boolean playerDamaged, bulletPassPlayer;
	
	private FileHandle ssDir;
	private int ssFilename;
	
	public RangeProfile(){
		this(null);
	}
	
	public RangeProfile(FileHandle fh){
		reset(null);
		ssDir = fh;
		if(ssDir != null){
			ssFilename = ssDir.list().length;
		}
	}
	
	/**
	 * Save previous profile (if available) to target directory and reset
	 */
	public void reset(FileHandle fh){
		if(fh != null && logs.size() > 0){
			save(fh.child("range_profile.txt"));
		}
		pendingSpeed = -1;
		pendingDistance = -1;
		playerDamaged = false;
		bulletPassPlayer = false;
		sessionLogged = false;
		logs.clear();
	}
	
	public void preUpdate(LevelSnapshot snapshot){
		if(snapshot.playerState.jumping && !sessionLogged){
			String iden = snapshot.enemy.identifier;
			pendingSpeed = Integer.parseInt(iden.substring(iden.lastIndexOf("_")+1));
			if(snapshot.tempRect.size() > 0){
				Vector2 firstAttackPos = new Vector2();
				snapshot.tempRect.values().iterator().next().getCenter(firstAttackPos);
				Vector2 playerPos = new Vector2();
				snapshot.playerRect.getCenter(playerPos);
				pendingDistance = (int)firstAttackPos.dst(playerPos);
			}
			if(ssDir != null){
				ScreenshotUtility.takeScreenshot(ssDir, ""+ssFilename);
				ssFilename++;
			}
			sessionLogged = true;
		}
		if(snapshot.player.getBaseHP() < snapshot.player.maxhp){
			playerDamaged = true;
		}
		for(DynamicEntity dyn : snapshot.tempRect.keySet()){
			if(snapshot.player.getWorldCollider().x - dyn.getWorldCollider().x >= 64){
				bulletPassPlayer = true;
			}
		}
	}
	
	public boolean shouldEndSession(){
		return playerDamaged || bulletPassPlayer;
	}
	
	/**
	 * Call when current range profiling session should end. Return true if the player is damaged during the session
	 * OR the session ends prematurely (end before enemy's first shoot)
	 */
{'fraction_non_alphanumeric': 0.1332916145181477, 'fraction_numerical': 0.008969545264914476, 'mean_word_length': 3.8823828920570267, 'pattern_counts': {'":': 0, '<': 34, '<?xml version=': 0, '>': 26, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4026480', 'n_tokens_mistral': 3621, 'n_tokens_neox': 3044, 'n_words': 703}