<commit_before>package main

import (
	"bufio"
	"encoding/json"
	"flag"
	"fmt"
	"github.com/pkg/errors"
	"log"
	"math/rand"
	"net"
	"os"
	"sort"
	"strings"
	"time"
)

const road_width = 40
const road_lenght = 20
const car_width = 14
const car_lenght = 7
const result_width = 76
const max_players_in_top = 10
const speed_factor = 10500

type Config struct {
	Log                 *log.Logger
	AcidPath, ScorePath string
}

type Point struct {
	X, Y int
}

type GameData struct {
	Roads              [][]byte
	Car, Clear, Splash []byte
	Top                []Player
}

type RoundData struct {
	player                                   Player
	CarPosition, bombPosition, bonusPosition Point
	BombFactor, BonusFactor, Speed           int
	GameOver                                 []byte
}

type Player struct {
	Name  string
	Score int64
}

type Players []Player

func (p Players) Len() int           { return len(p) }
func (p Players) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
func (p Players) Less(i, j int) bool { return p[i].Score > p[j].Score }

func generateRoads(size int) [][]byte {
	roads := make([][]byte, size)
	for offset := 0; offset < size; offset++ {
		roads[offset] = make([]byte, road_width*road_lenght)
		for row := 0; row < road_lenght; row++ {
			for column := 0; column < road_width; column++ {
				var symbol byte
				if column == 0 || column == road_width-2 {
					symbol = byte('|')
				} else if column == road_width-1 {
					symbol = byte('\n')
				} else if column == road_width/2-1 {
					if (row-offset)%size == 0 {
						symbol = byte('|')
					} else {
						symbol = byte(' ')
					}
				} else {
					symbol = byte(' ')
				}
				roads[offset][row*road_width+column] = symbol
			}
		}
	}
	return roads
}

func getAcid(conf *Config, fileName string) ([]byte, error) {
	fileStat, err := os.Stat(conf.AcidPath + "/" + fileName)
	if err != nil {
		conf.Log.Printf("Acid %s does not exist: %v\n", fileName, err)
		return []byte{}, err
	}

	acid := make([]byte, fileStat.Size())
	f, err := os.OpenFile(conf.AcidPath+"/"+fileName, os.O_RDONLY, os.ModePerm)
	if err != nil {
		conf.Log.Printf("Error while opening %s: %v\n", fileName, err)
		os.Exit(1)
	}
	defer f.Close()

	f.Read(acid)

	return acid, nil
}

func updatePosition(conn net.Conn, position *Point) {
	for {
		direction := make([]byte, 1)

		_, err := conn.Read(direction)
		if err != nil {
			return
		}

		switch direction[0] {
		case 68:
			// Left
			position.X--
		case 67:
			// Right
			position.X++
		case 65:
			// Up
			position.Y--
		case 66:
			// Down
			position.Y++
		}
	}
}

func updateScore(roundData *RoundData) {
	for {
		roundData.player.Score++
		time.Sleep(time.Duration(roundData.Speed) * time.Millisecond)
	}

}

func readName(conf *Config, conn net.Conn, gameData *GameData) (string, error) {
	conn.Write(gameData.Splash)
	io := bufio.NewReader(conn)
	line, err := io.ReadString('\n')
	if err != nil {
		conf.Log.Println("Error while name reading", err)
		return "", err
	}
	name := strings.Replace(line, "\n", "", -1)
	if name == "" {
		conf.Log.Println("Empty name")
		return "", errors.New("Empty name")
	}
	if len(name) > result_width/2 {
		conf.Log.Println("Too long name")
		return "", errors.New("Too long name")
	}
	return name, nil
}

func recalculatePlayers(gameData *GameData, roundData *RoundData) {
	// Then we check on which place is current player
	inserted := false
	for _, player := range gameData.Top {
		if roundData.player.Score >= player.Score {
			// Squash all players
			for i, player := range gameData.Top {
				if roundData.player.Name == player.Name {
					gameData.Top[i].Score = roundData.player.Score
					inserted = true
					break
				}
			}

			break
		}
	}

	// Insert new record to the end of slice
	if !inserted {
		gameData.Top = append(gameData.Top, roundData.player)
	}

	// Resort the slice
	sort.Sort(Players(gameData.Top))<commit_msg>Fix squash all players<commit_after>package main

import (
	"bufio"
	"encoding/json"
	"flag"
	"fmt"
	"github.com/pkg/errors"
	"log"
	"math/rand"
	"net"
	"os"
	"sort"
	"strings"
	"time"
)

const road_width = 40
const road_lenght = 20
const car_width = 14
const car_lenght = 7
const result_width = 76
const max_players_in_top = 10
const speed_factor = 10500

type Config struct {
	Log                 *log.Logger
	AcidPath, ScorePath string
}

type Point struct {
	X, Y int
}

type GameData struct {
	Roads              [][]byte
	Car, Clear, Splash []byte
	Top                []Player
}

type RoundData struct {
	player                                   Player
	CarPosition, bombPosition, bonusPosition Point
	BombFactor, BonusFactor, Speed           int
	GameOver                                 []byte
}

type Player struct {
	Name  string
	Score int64
}

type Players []Player

func (p Players) Len() int           { return len(p) }
func (p Players) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
func (p Players) Less(i, j int) bool { return p[i].Score > p[j].Score }

func generateRoads(size int) [][]byte {
	roads := make([][]byte, size)
	for offset := 0; offset < size; offset++ {
		roads[offset] = make([]byte, road_width*road_lenght)
		for row := 0; row < road_lenght; row++ {
			for column := 0; column < road_width; column++ {
				var symbol byte
				if column == 0 || column == road_width-2 {
					symbol = byte('|')
				} else if column == road_width-1 {
					symbol = byte('\n')
				} else if column == road_width/2-1 {
					if (row-offset)%size == 0 {
						symbol = byte('|')
					} else {
						symbol = byte(' ')
					}
				} else {
					symbol = byte(' ')
				}
				roads[offset][row*road_width+column] = symbol
			}
		}
	}
	return roads
}

func getAcid(conf *Config, fileName string) ([]byte, error) {
	fileStat, err := os.Stat(conf.AcidPath + "/" + fileName)
	if err != nil {
		conf.Log.Printf("Acid %s does not exist: %v\n", fileName, err)
		return []byte{}, err
	}

	acid := make([]byte, fileStat.Size())
	f, err := os.OpenFile(conf.AcidPath+"/"+fileName, os.O_RDONLY, os.ModePerm)
	if err != nil {
		conf.Log.Printf("Error while opening %s: %v\n", fileName, err)
		os.Exit(1)
	}
	defer f.Close()

	f.Read(acid)

	return acid, nil
}

func updatePosition(conn net.Conn, position *Point) {
	for {
		direction := make([]byte, 1)

		_, err := conn.Read(direction)
		if err != nil {
			return
		}

		switch direction[0] {
		case 68:
			// Left
			position.X--
		case 67:
			// Right
			position.X++
		case 65:
			// Up
			position.Y--
		case 66:
			// Down
			position.Y++
		}
	}
}

func updateScore(roundData *RoundData) {
	for {
		roundData.player.Score++
		time.Sleep(time.Duration(roundData.Speed) * time.Millisecond)
	}

}

func readName(conf *Config, conn net.Conn, gameData *GameData) (string, error) {
	conn.Write(gameData.Splash)
	io := bufio.NewReader(conn)
	line, err := io.ReadString('\n')
	if err != nil {
		conf.Log.Println("Error while name reading", err)
		return "", err
	}
	name := strings.Replace(line, "\n", "", -1)
	if name == "" {
		conf.Log.Println("Empty name")
		return "", errors.New("Empty name")
	}
	if len(name) > result_width/2 {
		conf.Log.Println("Too long name")
		return "", errors.New("Too long name")
	}
	return name, nil
}

func recalculatePlayers(gameData *GameData, roundData *RoundData) {
	// Then we check on which place is current player
	processed := false
	for _, player := range gameData.Top {
		if roundData.player.Score >= player.Score || len(gameData.Top) < max_players_in_top {
			// Squash all players
			for i, player := range gameData.Top {
				if roundData.player.Name == player.Name {
					if roundData.player.Score >= player.Score {
						gameData.Top[i].Score = roundData.player.Score
					}
					processed = true
					break
				}
			}
			break
		}
	}

	// Insert new record to the end of slice
	if !processed {
		gameData.Top = append(gameData.Top, roundData.player)
	}

	// Resort the slice
	sort.Sort(Players(gameData.Top))
{'fraction_non_alphanumeric': 0.14566430020283977, 'fraction_numerical': 0.010141987829614604, 'mean_word_length': 2.767430754536772, 'pattern_counts': {'":': 0, '<': 10, '<?xml version=': 0, '>': 10, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1926932', 'n_tokens_mistral': 3181, 'n_tokens_neox': 2814, 'n_words': 751}