<commit_before>#!/usr/bin/env python3
# -*- coding: Utf-8 -*-

"""
Swap

A puzzle game with a grid of blocks. Form associations of blocks by
swapping blocks to destroy them!

Modes:

Survival
Battle vs CPU/Human
	Stamina (life bar)
	Projectile (throw blocks to opponent)

"""

import sys
from random import randrange
import time
import itertools

import logging
logging.basicConfig(filename='swap.log', filemode='w', level=logging.DEBUG, \
format='%(asctime)s %(message)s')
LOG = logging.getLogger(__name__)
LOG.addHandler(logging.NullHandler())

LOG.info("Starting Swap")

RESET_COLOR = '\033[0m'
FG_DCOLORS = ['\033[90m', '\033[91m', '\033[93m', '\033[94m', '\033[92m', '\033[95m', '\033[96m']
BG_LCOLORS = ['\033[40m', '\033[101m', '\033[103m', '\033[104m', '\033[102m', '\033[105m', '\033[106m']
BG_DCOLORS = ['\033[40m', '\033[41m', '\033[43m', '\033[44m', '\033[42m', '\033[45m', '\033[46m']
fgcolors = lambda i: FG_DCOLORS[i] if i < 7 else '\033[97m'
bgcolors = lambda i: BG_DCOLORS[i] if i < 7 else '\033[97m'
SCORES = [10, 100, 500, 2000, 5000, 10000, 20000, 50000, 100000, 200000, 500000, 1000000]
scoreIt = lambda x: SCORES[x-3] if x <= 10 else 0#10 ** ((x-2)

class Game(object):

	def __init__(self):
		self.swapperPos = (0, 0)

		self.score = 0
		self.scoreMultiplier = 1

		self.grid = Grid(15, 20, 4)

		self.state = GameState()

	def update(self):

		if self.state.name == "falling":
			if self.state.status == "ending":
				isLastStep = self.grid.fallStep()
				if not isLastStep:
					self.state.jumpTo("falling", .1)
				else:
					self.scoreMultiplier = 1
					combos = self.grid.testComboAll()
					if combos:
						self.state.jumpTo("combo", 1., combos)
					else:
						self.state.jumpTo("running", .5)

		elif self.state.name == "combo":
			if self.state.status == "ending":
				self.processCombo(self.state.data)
				self.state.jumpTo("falling", .1)

		elif self.state.name == "running":
			if self.state.status == "starting":
				self.swapperPos = randrange(self.grid.width-1), randrange(self.grid.height-1)
			if self.state.status == "ending":
				self.grid.swap(*self.swapperPos)

				self.state.jumpTo("falling", .1)

		elif self.state.name == "init":
			self.state.jumpTo("running", 1.)

		self.state.update()

	def processCombo(self, combos):
		combosPos = set(itertools.chain.from_iterable(combos))
		for combo in combos:
			self.score += scoreIt(len(combo)) * self.scoreMultiplier
		self.scoreMultiplier += 1
		for pos in combosPos: # Remove combos
			self.grid[pos] = 0

class GameState(object):
	"""Represents the current state of the game

A game state can have finite or infinite duration (None value).
A status attribute describe whether the state is starting, ongoing or ending.
If necessary, data can be stored for the purpose of game state logic."""

	def __init__(self):
		# "init", "running", "falling", "combo"
		self.name = "init"
		self.data = None # Data conveyed by the state
		self.remainingTime = None
		self.duration = None
		self.status = "starting" # One of "starting", "ongoing", "ending"

		self.lastTime = time.time()

	def __repr__(self):
		return "GameState({self.name},{self.status},{self.remainingTime:.2f},{self.duration},{self.data})".format(self=self)

	def update(self):
		if self.remainingTime != None and self.remainingTime <= 0:
			self.status = "ending"
		elif self.status == "starting" and self.remainingTime != self.duration:
			self.status = "ongoing"

		currentTime = time.time()
		if self.remainingTime is not None:
			self.remainingTime -= currentTime - self.lastTime
		self.lastTime = currentTime

		LOG.info("%s", repr(self))

	def jumpTo(self, name, duration=None, data=None):
		self.name = name
		self.duration = duration
		self.remainingTime = duration
		self.status = "starting"
		self.data = data

class Grid(object):

	def __init__(self, width=None, height=None, nbSymbols=5, data=None):
		"""nbSymbols includes 0 (no block)"""
		if data:
			assert len(data) >= 3 and len(data[0]) >= 3, 'grid too small!'
			self.width = len(data)
			self.height = len(data[0])
			self.nbSymbols = nbSymbols
			self._grid = data
		else:
			assert width >= 3 and height >= 3, 'grid too small!'
			self.width = width<commit_msg>Changed game state system, yet to test and use<commit_after>#!/usr/bin/env python3
# -*- coding: Utf-8 -*-

"""
Swap

A puzzle game with a grid of blocks. Form associations of blocks by
swapping blocks to destroy them!

Modes:

Survival
Battle vs CPU/Human
	Stamina (life bar)
	Projectile (throw blocks to opponent)

"""

import sys
from random import randrange
import time
import itertools
from collections import UserDict

import logging
logging.basicConfig(filename='swap.log', filemode='w', level=logging.DEBUG, \
format='%(asctime)s %(message)s')
LOG = logging.getLogger(__name__)
LOG.addHandler(logging.NullHandler())

LOG.info("Starting Swap")

RESET_COLOR = '\033[0m'
FG_DCOLORS = ['\033[90m', '\033[91m', '\033[93m', '\033[94m', '\033[92m', '\033[95m', '\033[96m']
BG_LCOLORS = ['\033[40m', '\033[101m', '\033[103m', '\033[104m', '\033[102m', '\033[105m', '\033[106m']
BG_DCOLORS = ['\033[40m', '\033[41m', '\033[43m', '\033[44m', '\033[42m', '\033[45m', '\033[46m']
fgcolors = lambda i: FG_DCOLORS[i] if i < 7 else '\033[97m'
bgcolors = lambda i: BG_DCOLORS[i] if i < 7 else '\033[97m'
SCORES = [1, 5, 20, 80, 200, 500, 1000, 2000, 4000, 6000, 8000, 10000]
scoreIt = lambda x: SCORES[x-3] if x <= 10 else 0

class Game(object):

	def __init__(self):
		self.swapperPos = (0, 0)

		self.score = 0
		self.scoreMultiplier = 1

		self.grid = Grid(15, 20, 4)

		self.state = StateMachine()

	"""def update(self):

		if self.state.name == "running":
			if self.state.status == "starting":
				self.swapperPos = randrange(self.grid.width-1), randrange(self.grid.height-1)
			elif self.state.status == "ending":
				self.grid.swap(*self.swapperPos)

				isLastStep = self.grid.fallStep()
				if isLastStep:
					combos = self.grid.testComboAll()
					if combos:
						self.processCombos(combos)
					else:
						self.scoreMultiplier = 1
				self.state.jumpTo("running", .2)

		self.state.update()
"""
	def update(self):

		if self.state.name == "falling":
			if self.state.status == "ending":
				isLastStep = self.grid.fallStep()
				if not isLastStep:
					self.state.jumpTo("falling", .1)
				else:
					combos = self.grid.testComboAll()
					if combos:
						self.state.jumpTo("combo", 1., combos)
					else:
						self.scoreMultiplier = 1
						self.state.jumpTo("running", .5)

		elif self.state.name == "combo":
			if self.state.status == "ending":
				self.processCombos(self.state.data)
				self.state.jumpTo("falling", .1)

		elif self.state.name == "running":
			if self.state.status == "starting":
				self.swapperPos = randrange(self.grid.width-1), randrange(self.grid.height-1)
			if self.state.status == "ending":
				self.grid.swap(*self.swapperPos)
				self.state.jumpTo("falling", .1)

		elif self.state.name == "init":
			self.state.jumpTo("running", 1.)

		self.state.update()

	def processCombos(self, combos):
		combosPos = set(itertools.chain.from_iterable(combos))
		for combo in combos:
			self.score += scoreIt(len(combo)) * self.scoreMultiplier
		self.scoreMultiplier += 1
		for pos in combosPos: # Remove combos
			self.grid[pos] = 0

class StateMachine(dict): # TODO: test and use
	"""Represents a dynamic concurrent state machine"""

	def __init__(self):
		self.lastTime = time.time()

	def new(self, stateName, duration=None, data=None):
		self[stateName] = State(duration, data)

	def alter(self, oldStateName, stateName, duration=None, data=None):
		self[stateName] = State(duration, data)
		del self[oldStateName]

	def update(self):
		currentTime = time.time()
		dt = currentTime - self.lastTime

		for state in self.itervalues():
			if state.remainingTime != None and state.remainingTime <= 0:
				state.status = "ending"
			elif state.status == "starting" and state.remainingTime != state.duration:
				state.status = "ongoing"

			if state.remainingTime is not None:
				state.remainingTime -= dt

		self.lastTime = currentTime

		LOG.info("%s", repr(self))

class State(Struct):
	"""Represents a game state

A state can have finite or infinite duration (None value).
A status attribute describe whether the state is starting, ongoing or ending.
If necessary, data can be stored for the purpose of state logic."""

	def __init__(self, duration=None, data=None):
		self.data = data # Data conveyed by the state
		self.remainingTime = duration
		self.duration = duration
		self.status = "starting" # One of "starting", "ongoing", "ending"

'''class State(object):
	"""Represents a game state

A state can have finite or infinite duration (None value).
A status attribute describe whether the state is starting, ongoing or ending.
If necessary, data can be stored for the purpose of state logic."""

	def __init__(self, name="init"):
		self.name = name
		self.data = None # Data conveyed by the state
		self.remainingTime = None
		self.duration = None
		self.status = "starting" # One of "starting", "ongoing", "ending"

		self.lastTime = time.time()

	def __repr__(self):
		return "GameState({self.name},{self.status},{self.remainingTime:.2f},{self.duration},{self.data})".format(self=self)

	def update(self):
		if self.remainingTime != None and self.remainingTime <= 0:
			self.status = "ending"
		elif self.status == "starting" and self.remainingTime != self.duration:
			self.status = "ongoing"

		currentTime = time.time()
		if self.remainingTime is not None:
			self.remainingTime -= currentTime - self.lastTime
		self.lastTime = currentTime

		LOG.info("%s", repr(self))

	def jumpTo(self, name, duration=None, data=None):
		self.name = name
		self.duration = duration
		self.remainingTime = duration
		self.status = "starting"
		self.data = data'''

class Grid(object):

	def __init__(self, width=None, height=None, nbSymbols=5, data=None):
		"""nbSymbols includes 0 (no block)"""
		if data:
			assert len(data) >= 3 and len(data[0]) >= 3, 'grid too small!'
			self.width = len(data)
			self.height = len(data[0])
			self.nbSymbols = nbSymbols
			self._grid = data
		else:
			assert width >= 3 and height >= 3, 'grid too small!'
			self.width = width
{'fraction_non_alphanumeric': 0.15166388534406597, 'fraction_numerical': 0.041916167664670656, 'mean_word_length': 3.9122468659594984, 'pattern_counts': {'":': 19, '<': 12, '<?xml version=': 0, '>': 11, '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': '3758729', 'n_tokens_mistral': 4203, 'n_tokens_neox': 3512, 'n_words': 947}