Compare commits
12 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
fbe95c4c04 | ||
|
a2c2e9faf6 | ||
|
c8a7f22a45 | ||
|
4abcfc2178 | ||
|
70f9ad4d99 | ||
|
d29d2e53bd | ||
|
965636544e | ||
|
12b7224510 | ||
|
1d6505a2ca | ||
|
6cb6de28fc | ||
|
76e1781864 | ||
|
3b223dfea2 |
183
.gitignore
vendored
Normal file
183
.gitignore
vendored
Normal file
@ -0,0 +1,183 @@
|
||||
/target/
|
||||
!.mvn/wrapper/maven-wrapper.jar
|
||||
|
||||
### STS ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
|
||||
|
||||
# Created by https://www.gitignore.io/api/git,java,maven,eclipse,windows
|
||||
|
||||
### Eclipse ###
|
||||
|
||||
.metadata
|
||||
bin/
|
||||
tmp/
|
||||
*.tmp
|
||||
*.bak
|
||||
*.swp
|
||||
*~.nib
|
||||
local.properties
|
||||
.settings/
|
||||
.loadpath
|
||||
.recommenders
|
||||
|
||||
# External tool builders
|
||||
.externalToolBuilders/
|
||||
|
||||
# Locally stored "Eclipse launch configurations"
|
||||
*.launch
|
||||
|
||||
# PyDev specific (Python IDE for Eclipse)
|
||||
*.pydevproject
|
||||
|
||||
# CDT-specific (C/C++ Development Tooling)
|
||||
.cproject
|
||||
|
||||
# CDT- autotools
|
||||
.autotools
|
||||
|
||||
# PDT-specific (PHP Development Tools)
|
||||
.buildpath
|
||||
|
||||
# sbteclipse plugin
|
||||
.target
|
||||
|
||||
# Tern plugin
|
||||
.tern-project
|
||||
|
||||
# TeXlipse plugin
|
||||
.texlipse
|
||||
|
||||
# Code Recommenders
|
||||
.recommenders/
|
||||
|
||||
# Annotation Processing
|
||||
.apt_generated/
|
||||
|
||||
# Scala IDE specific (Scala & Java development for Eclipse)
|
||||
.cache-main
|
||||
.scala_dependencies
|
||||
.worksheet
|
||||
|
||||
# Annotation Processing
|
||||
|
||||
.sts4-cache/
|
||||
|
||||
### Git ###
|
||||
# Created by git for backups. To disable backups in Git:
|
||||
# $ git config --global mergetool.keepBackup false
|
||||
*.orig
|
||||
|
||||
# Created by git when using merge tools for conflicts
|
||||
*.BACKUP.*
|
||||
*.BASE.*
|
||||
*.LOCAL.*
|
||||
*.REMOTE.*
|
||||
*_BACKUP_*.txt
|
||||
*_BASE_*.txt
|
||||
*_LOCAL_*.txt
|
||||
*_REMOTE_*.txt
|
||||
|
||||
### Java ###
|
||||
# Compiled class file
|
||||
*.class
|
||||
|
||||
# Log file
|
||||
*.log
|
||||
|
||||
# BlueJ files
|
||||
*.ctxt
|
||||
|
||||
# Mobile Tools for Java (J2ME)
|
||||
.mtj.tmp/
|
||||
|
||||
# Package Files #
|
||||
*.jar
|
||||
*.war
|
||||
*.nar
|
||||
*.ear
|
||||
*.zip
|
||||
*.tar.gz
|
||||
*.rar
|
||||
|
||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||
hs_err_pid*
|
||||
|
||||
### Maven ###
|
||||
target/
|
||||
pom.xml.tag
|
||||
pom.xml.releaseBackup
|
||||
pom.xml.versionsBackup
|
||||
pom.xml.next
|
||||
release.properties
|
||||
dependency-reduced-pom.xml
|
||||
buildNumber.properties
|
||||
.mvn/timing.properties
|
||||
.mvn/wrapper/maven-wrapper.jar
|
||||
|
||||
### Windows ###
|
||||
# Windows thumbnail cache files
|
||||
Thumbs.db
|
||||
ehthumbs.db
|
||||
ehthumbs_vista.db
|
||||
|
||||
# Dump file
|
||||
*.stackdump
|
||||
|
||||
# Folder config file
|
||||
[Dd]esktop.ini
|
||||
|
||||
# Recycle Bin used on file shares
|
||||
$RECYCLE.BIN/
|
||||
|
||||
# Windows Installer files
|
||||
*.cab
|
||||
*.msi
|
||||
*.msix
|
||||
*.msm
|
||||
*.msp
|
||||
|
||||
# Windows shortcuts
|
||||
*.lnk
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
/build/
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
|
||||
### Some additional ignores (sort later)
|
||||
*.DS_Store
|
||||
*.sw?
|
||||
.#*
|
||||
*#
|
||||
*~
|
||||
bin
|
||||
build
|
||||
target
|
||||
*.sublime-*
|
||||
/scratch
|
||||
.gradle
|
||||
README.html
|
||||
.exercism
|
||||
/target/
|
||||
/.idea/
|
3
.idea/.gitignore
generated
vendored
Normal file
3
.idea/.gitignore
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
15
.idea/compiler.xml
generated
Normal file
15
.idea/compiler.xml
generated
Normal file
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<annotationProcessing>
|
||||
<profile default="true" name="Default" enabled="true" />
|
||||
<profile name="Maven default annotation processors profile" enabled="true">
|
||||
<sourceOutputDir name="target/generated-sources/annotations" />
|
||||
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
|
||||
<outputRelativeToContentRoot value="true" />
|
||||
<module name="social_altruism" />
|
||||
</profile>
|
||||
</annotationProcessing>
|
||||
<bytecodeTargetLevel target="19" />
|
||||
</component>
|
||||
</project>
|
6
.idea/google-java-format.xml
generated
Normal file
6
.idea/google-java-format.xml
generated
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="GoogleJavaFormatSettings">
|
||||
<option name="enabled" value="true" />
|
||||
</component>
|
||||
</project>
|
17
.idea/gradle.xml
generated
Normal file
17
.idea/gradle.xml
generated
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="GradleMigrationSettings" migrationVersion="1" />
|
||||
<component name="GradleSettings">
|
||||
<option name="linkedExternalProjectsSettings">
|
||||
<GradleProjectSettings>
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="gradleJvm" value="corretto-19" />
|
||||
<option name="modules">
|
||||
<set>
|
||||
<option value="$PROJECT_DIR$" />
|
||||
</set>
|
||||
</option>
|
||||
</GradleProjectSettings>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
35
.idea/jarRepositories.xml
generated
Normal file
35
.idea/jarRepositories.xml
generated
Normal file
@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="RemoteRepositoriesConfiguration">
|
||||
<remote-repository>
|
||||
<option name="id" value="central" />
|
||||
<option name="name" value="Central Repository" />
|
||||
<option name="url" value="https://repo.maven.apache.org/maven2" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="MavenRepo" />
|
||||
<option name="name" value="MavenRepo" />
|
||||
<option name="url" value="https://repo.maven.apache.org/maven2/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="central" />
|
||||
<option name="name" value="Maven Central repository" />
|
||||
<option name="url" value="https://repo1.maven.org/maven2" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="jboss.community" />
|
||||
<option name="name" value="JBoss Community repository" />
|
||||
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="MavenLocal" />
|
||||
<option name="name" value="MavenLocal" />
|
||||
<option name="url" value="file:$MAVEN_REPOSITORY$/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="akka-repository" />
|
||||
<option name="name" value="Akka library repository" />
|
||||
<option name="url" value="https://repo.akka.io/maven" />
|
||||
</remote-repository>
|
||||
</component>
|
||||
</project>
|
6
.idea/jpa-buddy.xml
generated
Normal file
6
.idea/jpa-buddy.xml
generated
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="JpaBuddyIdeaProjectConfig">
|
||||
<option name="renamerInitialized" value="true" />
|
||||
</component>
|
||||
</project>
|
16
.idea/misc.xml
generated
Normal file
16
.idea/misc.xml
generated
Normal file
@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||
<component name="MavenProjectsManager">
|
||||
<option name="originalFiles">
|
||||
<list>
|
||||
<option value="$PROJECT_DIR$/pom.xml" />
|
||||
</list>
|
||||
</option>
|
||||
<option name="workspaceImportForciblyTurnedOn" value="true" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" project-jdk-name="corretto-19" project-jdk-type="JavaSDK" />
|
||||
<component name="ProjectType">
|
||||
<option name="id" value="jpab" />
|
||||
</component>
|
||||
</project>
|
124
.idea/uiDesigner.xml
generated
Normal file
124
.idea/uiDesigner.xml
generated
Normal file
@ -0,0 +1,124 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Palette2">
|
||||
<group name="Swing">
|
||||
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
|
||||
</item>
|
||||
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
|
||||
</item>
|
||||
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
|
||||
</item>
|
||||
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.svg" removable="false" auto-create-binding="false" can-attach-label="true">
|
||||
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
|
||||
</item>
|
||||
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
|
||||
<initial-values>
|
||||
<property name="text" value="Button" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
|
||||
<initial-values>
|
||||
<property name="text" value="RadioButton" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
|
||||
<initial-values>
|
||||
<property name="text" value="CheckBox" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
|
||||
<initial-values>
|
||||
<property name="text" value="Label" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||
<preferred-size width="150" height="-1" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||
<preferred-size width="150" height="-1" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||
<preferred-size width="150" height="-1" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
|
||||
<preferred-size width="200" height="200" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
|
||||
<preferred-size width="200" height="200" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
|
||||
</item>
|
||||
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
|
||||
<preferred-size width="-1" height="20" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
|
||||
</item>
|
||||
</group>
|
||||
</component>
|
||||
</project>
|
7
.idea/vcs.xml
generated
Normal file
7
.idea/vcs.xml
generated
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
23
README.txt
Normal file
23
README.txt
Normal file
@ -0,0 +1,23 @@
|
||||
|
||||
Juego del bien público
|
||||
----------------------
|
||||
- Varios jugadores.
|
||||
- Reciben N monedas al comienzo.
|
||||
- Hay un bote central.
|
||||
|
||||
- Cada turno se elige con cuántas monedas uno colabora al bote.
|
||||
- Entonces, el contenido del bote se multiplica por dos y se divide entre todos los jugadores.
|
||||
- Pasadas N rondas, el jugador se queda con lo que ganó + monedas iniciales.
|
||||
|
||||
- Tipos de jugadores:
|
||||
- Pícaro: no colabora nunca.
|
||||
- Santo: colabora siempre.
|
||||
- Justiciero: colabora si y solo si todos los jugadores han colaborado en el turno anterior.
|
||||
|
||||
Comprobar distribución de ganancia según variación en tipo de jugadores; Pícaro, santo o justiciero.
|
||||
|
||||
10 jugadores, 100 turnos, 100 monedas iniciales.
|
||||
|
||||
|
||||
Comprobar cómo de dispuesta está la gente a contribuir a un bien, que será compartido por todos por igual,
|
||||
hayan contribuido o no.
|
122
pom.xml
Normal file
122
pom.xml
Normal file
@ -0,0 +1,122 @@
|
||||
<!-- #build-sample -->
|
||||
<project>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>hello-akka-java</groupId>
|
||||
<artifactId>SocialAltruism</artifactId>
|
||||
<version>1.0</version>
|
||||
|
||||
<properties>
|
||||
<akka.version>2.9.0</akka.version>
|
||||
</properties>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>akka-repository</id>
|
||||
<name>Akka library repository</name>
|
||||
<url>https://repo.akka.io/maven</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-reload4j -->
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-reload4j</artifactId>
|
||||
<version>2.0.9</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.typesafe.akka</groupId>
|
||||
<artifactId>akka-actor-typed_2.13</artifactId>
|
||||
<version>${akka.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.typesafe.akka</groupId>
|
||||
<artifactId>akka-actor-testkit-typed_2.13</artifactId>
|
||||
<version>${akka.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.13.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.awaitility</groupId>
|
||||
<artifactId>awaitility</artifactId>
|
||||
<version>4.2.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.awaitility</groupId>
|
||||
<artifactId>awaitility-proxy</artifactId>
|
||||
<version>3.1.6</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/org.hamcrest/hamcrest -->
|
||||
<dependency>
|
||||
<groupId>org.hamcrest</groupId>
|
||||
<artifactId>hamcrest</artifactId>
|
||||
<version>2.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/org.mockito/mockito-core -->
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>5.8.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/net.bytebuddy/byte-buddy -->
|
||||
<dependency>
|
||||
<groupId>net.bytebuddy</groupId>
|
||||
<artifactId>byte-buddy</artifactId>
|
||||
<version>1.14.11</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.30</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.11.0</version>
|
||||
<configuration>
|
||||
<source>19</source>
|
||||
<target>19</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<configuration>
|
||||
<executable>java</executable>
|
||||
<arguments>
|
||||
<argument>-classpath</argument>
|
||||
<classpath />
|
||||
<argument>dev.freireservices.social_altruism.chat.PotQuickStart</argument>
|
||||
</arguments>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
@ -0,0 +1,84 @@
|
||||
package dev.freireservices.social_altruism.chat;
|
||||
|
||||
import akka.actor.typed.ActorRef;
|
||||
import akka.actor.typed.ActorSystem;
|
||||
import akka.actor.typed.Behavior;
|
||||
import akka.actor.typed.Terminated;
|
||||
import akka.actor.typed.javadsl.Behaviors;
|
||||
import dev.freireservices.social_altruism.chat.participant.Participant;
|
||||
import dev.freireservices.social_altruism.chat.participant.ParticipantProtocol;
|
||||
import dev.freireservices.social_altruism.chat.potroom.PotRoom;
|
||||
import dev.freireservices.social_altruism.chat.potroom.PotRoomProtocol;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static dev.freireservices.social_altruism.chat.participant.ParticipantType.*;
|
||||
|
||||
public class PotQuickStart {
|
||||
|
||||
public static final int MONEDAS_INIT = 100;
|
||||
|
||||
public static void main(String[] args) {
|
||||
// #actor-system
|
||||
ActorSystem.create(Main.create(), "PotRoom");
|
||||
}
|
||||
|
||||
public static class Main {
|
||||
|
||||
static List<ActorRef<ParticipantProtocol.ParticipantMessage>> sessions = new ArrayList<>();
|
||||
|
||||
static final int numberOfParticipants = 3;
|
||||
static final int numberOfTurns = 100;
|
||||
|
||||
public static Behavior<Void> create() {
|
||||
return Behaviors.setup(
|
||||
context -> {
|
||||
ActorRef<PotRoomProtocol.PotRoomMessage> chatRoom =
|
||||
context.spawn(
|
||||
PotRoom.create(numberOfParticipants, numberOfTurns), "potRoom");
|
||||
|
||||
// Agregamos jugadores
|
||||
final var picaroZero = Participant.create(MONEDAS_INIT, PICARO);
|
||||
final var santoZero = Participant.create(MONEDAS_INIT, SANTO);
|
||||
final var justiZero = Participant.create(MONEDAS_INIT, JUSTICIERO);
|
||||
|
||||
sessions.add(context.spawn(picaroZero, "participante-picaro-0"));
|
||||
sessions.add(context.spawn(santoZero, "participante-santo-0"));
|
||||
sessions.add(context.spawn(justiZero, "participante-justiciero-0"));
|
||||
|
||||
// Entrar en pot
|
||||
for (ActorRef<ParticipantProtocol.ParticipantMessage> session : sessions) {
|
||||
chatRoom.tell(new PotRoomProtocol.EnterPot(session));
|
||||
}
|
||||
|
||||
/* for (int i = 0; i < numberOfTurns; i++) {
|
||||
// Participar en cada turno cantidad diferente
|
||||
for (ActorRef<ParticipantProtocol.ParticipantMessage> session : participants) {
|
||||
|
||||
// Pícaro
|
||||
if (session.path().name().contains("participante-0")) {
|
||||
chatRoom.tell(new PotRoomProtocol.PlayTurn(session, 0));
|
||||
// Justiciero
|
||||
} else if (session.path().name().contains("participante-1")) {
|
||||
|
||||
// ActorRef<Commands.RoomCommand> chatRoom, double pot,
|
||||
// ActorRef<Events.SessionEvent> replyTo)
|
||||
|
||||
chatRoom.tell(new PotRoomProtocol.PlayTurn(session, 1));
|
||||
// Santo
|
||||
} else if (session.path().name().contains("participante-2")) {
|
||||
chatRoom.tell(new PotRoomProtocol.PlayTurn(session, 2));
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
return Behaviors.receive(Void.class)
|
||||
.onSignal(Terminated.class, sig -> Behaviors.stopped())
|
||||
.build();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// #actor-system
|
||||
}
|
@ -0,0 +1,219 @@
|
||||
package dev.freireservices.social_altruism.chat.participant;
|
||||
|
||||
import akka.actor.typed.ActorRef;
|
||||
import akka.actor.typed.Behavior;
|
||||
import akka.actor.typed.javadsl.ActorContext;
|
||||
import akka.actor.typed.javadsl.Behaviors;
|
||||
import dev.freireservices.social_altruism.chat.participant.ParticipantProtocol.*;
|
||||
import dev.freireservices.social_altruism.chat.potroom.PotRoomProtocol.PotRoomMessage;
|
||||
import dev.freireservices.social_altruism.chat.potroom.SessionProtocol;
|
||||
import dev.freireservices.social_altruism.chat.potroom.SessionProtocol.SessionMessage;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
|
||||
import static dev.freireservices.social_altruism.chat.participant.ParticipantType.JUSTICIERO;
|
||||
import static dev.freireservices.social_altruism.chat.participant.ParticipantType.SANTO;
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
public class Participant {
|
||||
|
||||
private final ActorContext<ParticipantMessage> context;
|
||||
private ActorRef<PotRoomMessage> chatRoom;
|
||||
private ActorRef<SessionMessage> session;
|
||||
|
||||
private boolean collaborateSwitch;
|
||||
private int currentTurn;
|
||||
private double participantCoins;
|
||||
private final double initialCoins;
|
||||
private List<ActorRef<ParticipantMessage>> participants;
|
||||
private int totalTurns;
|
||||
private final ParticipantType participantType;
|
||||
|
||||
private Participant(
|
||||
ActorContext<ParticipantMessage> context,
|
||||
double participantCoins,
|
||||
ParticipantType participantType) {
|
||||
this.context = context;
|
||||
this.participantCoins = participantCoins;
|
||||
this.initialCoins = participantCoins;
|
||||
this.participantType = participantType;
|
||||
this.collaborateSwitch = participantType == JUSTICIERO || participantType == SANTO;
|
||||
}
|
||||
|
||||
public static Behavior<ParticipantMessage> create(
|
||||
int initialCoins, ParticipantType participantType) {
|
||||
return Behaviors.setup(ctx -> new Participant(ctx, initialCoins, participantType).behavior());
|
||||
}
|
||||
|
||||
public double decrementCoins(double coins) {
|
||||
this.participantCoins -= coins;
|
||||
|
||||
return coins;
|
||||
}
|
||||
|
||||
public void incrementCoins(double coins) {
|
||||
this.participantCoins += coins;
|
||||
}
|
||||
|
||||
private Behavior<ParticipantMessage> behavior() {
|
||||
return uninitialized();
|
||||
}
|
||||
|
||||
private Behavior<ParticipantMessage> uninitialized() {
|
||||
return Behaviors.receive(ParticipantMessage.class)
|
||||
.onMessage(SessionDenied.class, this::onSessionDenied)
|
||||
.onMessage(SessionGranted.class, x ->
|
||||
{
|
||||
onSessionGranted(x);
|
||||
return readyToStart();
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
private Behavior<ParticipantMessage> readyToStart() {
|
||||
return Behaviors.receive(ParticipantMessage.class)
|
||||
.onMessage(SessionStarted.class,
|
||||
x -> {
|
||||
onSessionStarted(x);
|
||||
return started();
|
||||
}
|
||||
)
|
||||
.build();
|
||||
}
|
||||
|
||||
private Behavior<ParticipantMessage> started() {
|
||||
return Behaviors.receive(ParticipantMessage.class)
|
||||
.onMessage(PotReturned.class, this::onPotReturned)
|
||||
.onMessage(SessionEnded.class, this::onSessionEnded)
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
private Behavior<ParticipantMessage> onSessionEnded(SessionEnded sessionEnded) {
|
||||
|
||||
context.getLog().info("Session ended for user: Stats: {}. Earned {} coins, profit {} %"
|
||||
, context.getSelf().path().name()
|
||||
, String.format("%.3f%n", getParticipantCoins() - getInitialCoins())
|
||||
, calculateProfit()
|
||||
);
|
||||
return Behaviors.stopped();
|
||||
}
|
||||
|
||||
private Behavior<ParticipantMessage> onSessionDenied(
|
||||
SessionDenied message) {
|
||||
context.getLog().info("cannot start chat room session: {}", message.reason());
|
||||
return Behaviors.stopped();
|
||||
}
|
||||
|
||||
private void onSessionGranted(
|
||||
SessionGranted message) {
|
||||
context.getLog().info("Session granted message received for {} ", context.getSelf().path().name());
|
||||
setChatRoom(message.chatRoom());
|
||||
setSession(message.session());
|
||||
}
|
||||
|
||||
private void onSessionStarted(
|
||||
SessionStarted startSession) {
|
||||
context.getLog().info("Session started for {} with {} participants", context.getSelf().path().name(), startSession.participants().size());
|
||||
resetCurrentTurn();
|
||||
setParticipants(startSession.participants());
|
||||
setTotalTurns(startSession.totalTurns());
|
||||
playTurnWithSmallDelay(startSession.replyTo());
|
||||
}
|
||||
|
||||
private void playTurnWithSmallDelay(ActorRef<SessionMessage> replyTo) {
|
||||
if (getParticipantCoins() > 0 && getCurrentTurn() < getTotalTurns()) {
|
||||
context.scheduleOnce(Duration.ofMillis(500),
|
||||
replyTo,
|
||||
new SessionProtocol.PlayTurn(
|
||||
replyTo,
|
||||
context.getSelf(),
|
||||
participants,
|
||||
getCurrentTurn(),
|
||||
getParticipationForCurrentTurn())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private double getParticipationForCurrentTurn() {
|
||||
var currentTurnCoins = getRandomNumberBetween(0, Math.floor(getParticipantCoins()));
|
||||
return isCollaborateSwitch() ? decrementCoins(currentTurnCoins) : 0;
|
||||
}
|
||||
|
||||
public static double getRandomNumberBetween(double min, double max) {
|
||||
SecureRandom secureRandom = new SecureRandom();
|
||||
return Math.round(secureRandom.nextDouble(max - min) + min);
|
||||
}
|
||||
|
||||
private Behavior<ParticipantMessage> onPotReturned(
|
||||
PotReturned potReturned) {
|
||||
context.getLog().info("Pot returned: {} for participant {}", String.format("%.2f", potReturned.returnedAmount()), potReturned.participant().path().name());
|
||||
incrementCoins(potReturned.returnedAmount());
|
||||
incrementCurrentTurn();
|
||||
context
|
||||
.getLog()
|
||||
.info(
|
||||
"Player {} has now {} coins; started with {} for a partial profit of: {} %",
|
||||
potReturned.participant().path().name(),
|
||||
String.format("%.3f", getParticipantCoins()),
|
||||
getInitialCoins(),
|
||||
calculateProfit());
|
||||
|
||||
// Still game?
|
||||
if (getParticipantCoins() > 1) {
|
||||
playTurnWithSmallDelay(potReturned.session());
|
||||
} else {
|
||||
context
|
||||
.getLog()
|
||||
.info(
|
||||
"Player {} has now {} coins; started with {} for a total profit of: {} %",
|
||||
potReturned.participant().path().name(),
|
||||
getParticipantCoins(),
|
||||
getInitialCoins(),
|
||||
calculateProfit());
|
||||
|
||||
context.getLog().info("END GAME");
|
||||
context.getLog().info("---------");
|
||||
context.getLog().info("END GAME");
|
||||
|
||||
context.stop(context.getSelf());
|
||||
Behaviors.stopped();
|
||||
|
||||
}
|
||||
adjustBehaviour(potReturned);
|
||||
return Behaviors.same();
|
||||
}
|
||||
|
||||
private void adjustBehaviour(PotReturned potReturned) {
|
||||
|
||||
switch (participantType) {
|
||||
case SANTO:
|
||||
setCollaborateSwitch(true);
|
||||
break;
|
||||
case PICARO:
|
||||
setCollaborateSwitch(false);
|
||||
break;
|
||||
case JUSTICIERO:
|
||||
// Tweak minimum amount to collaborate; average contribution must be at least the same.
|
||||
setCollaborateSwitch((potReturned.returnedAmount() / participants.size() >= getParticipationForCurrentTurn()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void resetCurrentTurn() {
|
||||
setCurrentTurn(0);
|
||||
}
|
||||
|
||||
public void incrementCurrentTurn() {
|
||||
setCurrentTurn(++this.currentTurn);
|
||||
}
|
||||
|
||||
private double calculateProfit() {
|
||||
return Math.round((getParticipantCoins() * 100) / getInitialCoins() - 100);
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
package dev.freireservices.social_altruism.chat.participant;
|
||||
|
||||
import akka.actor.typed.ActorRef;
|
||||
import dev.freireservices.social_altruism.chat.potroom.PotRoomProtocol.PotRoomMessage;
|
||||
import dev.freireservices.social_altruism.chat.potroom.SessionProtocol.SessionMessage;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ParticipantProtocol {
|
||||
public interface ParticipantMessage {
|
||||
}
|
||||
|
||||
enum Timeout implements ParticipantMessage {
|
||||
INSTANCE
|
||||
}
|
||||
|
||||
public record SessionGranted(
|
||||
ActorRef<PotRoomMessage> chatRoom,
|
||||
ActorRef<SessionMessage> session
|
||||
)
|
||||
implements ParticipantMessage {
|
||||
}
|
||||
|
||||
public record SessionStarted(
|
||||
ActorRef<PotRoomMessage> chatRoom,
|
||||
|
||||
ActorRef<SessionMessage> replyTo,
|
||||
List<ActorRef<ParticipantMessage>> participants,
|
||||
int totalTurns)
|
||||
implements ParticipantMessage {
|
||||
}
|
||||
|
||||
public record SessionDenied(String reason) implements ParticipantMessage {
|
||||
}
|
||||
|
||||
public record SessionEnded() implements ParticipantMessage {
|
||||
}
|
||||
|
||||
public record PotReturned(
|
||||
ActorRef<SessionMessage> session,
|
||||
ActorRef<ParticipantMessage> participant,
|
||||
double returnedAmount)
|
||||
implements ParticipantMessage {
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package dev.freireservices.social_altruism.chat.participant;
|
||||
|
||||
public enum ParticipantType {
|
||||
SANTO,
|
||||
JUSTICIERO,
|
||||
PICARO,
|
||||
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
package dev.freireservices.social_altruism.chat.potroom;
|
||||
|
||||
import akka.actor.typed.ActorRef;
|
||||
import akka.actor.typed.Behavior;
|
||||
import akka.actor.typed.javadsl.ActorContext;
|
||||
import akka.actor.typed.javadsl.Behaviors;
|
||||
import dev.freireservices.social_altruism.chat.potroom.PotRoomProtocol.EnterPot;
|
||||
import dev.freireservices.social_altruism.chat.potroom.PotRoomProtocol.PotRoomMessage;
|
||||
import dev.freireservices.social_altruism.chat.potroom.SessionProtocol.SessionMessage;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static dev.freireservices.social_altruism.chat.participant.ParticipantProtocol.*;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
@Getter
|
||||
public class PotRoom {
|
||||
private final ActorContext<PotRoomMessage> context;
|
||||
private final List<ActorRef<ParticipantMessage>> participants;
|
||||
|
||||
private final int totalTurns;
|
||||
private final int numberOfParticipants;
|
||||
|
||||
private PotRoom(
|
||||
ActorContext<PotRoomMessage> context,
|
||||
int numberOfParticipants,
|
||||
int totalTurns) {
|
||||
this.context = context;
|
||||
this.participants = new ArrayList<>();
|
||||
this.numberOfParticipants = numberOfParticipants;
|
||||
this.totalTurns = totalTurns;
|
||||
}
|
||||
|
||||
private Behavior<PotRoomMessage> onGetPotSession(
|
||||
ActorRef<PotRoomMessage> chatRoom, EnterPot enterPot) {
|
||||
|
||||
validate(enterPot);
|
||||
|
||||
context.getLog().info("Participant joined {} pot", enterPot.replyTo().path().name());
|
||||
|
||||
ActorRef<ParticipantMessage> participant = enterPot.replyTo();
|
||||
|
||||
participants.add(participant);
|
||||
|
||||
if (getNumberOfParticipants() == participants.size()) {
|
||||
context.getLog().info("All participants joined; pot is ready to start.");
|
||||
|
||||
ActorRef<SessionMessage> session =
|
||||
context.spawn(
|
||||
Session.create(participants, totalTurns),
|
||||
URLEncoder.encode(enterPot.replyTo().path().name(), UTF_8));
|
||||
|
||||
|
||||
// Communicate session start and share pot info with all participants
|
||||
//Fishy, probably could spare one..
|
||||
participants.forEach(p -> p.tell(new SessionGranted(chatRoom, session.narrow())));
|
||||
participants.forEach(p -> p.tell(new SessionStarted(chatRoom, session, participants, totalTurns)));
|
||||
|
||||
return createPotBehaviour(chatRoom);
|
||||
} else {
|
||||
// Waiting for more participants
|
||||
context.getLog().info("Waiting for {} more participant(s).", numberOfParticipants - participants.size());
|
||||
return Behaviors.same();
|
||||
}
|
||||
}
|
||||
|
||||
private void validate(EnterPot enterPot) {
|
||||
// Add check session started
|
||||
if (participants.stream()
|
||||
.anyMatch(
|
||||
s ->
|
||||
s.path()
|
||||
.name()
|
||||
.equals(URLEncoder.encode(enterPot.replyTo().path().name(), UTF_8)))) {
|
||||
|
||||
enterPot.replyTo().tell(new SessionDenied("Can only enter a pot once"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private Behavior<PotRoomMessage> createPotBehaviour(ActorRef<PotRoomMessage> chatRoom) {
|
||||
return Behaviors.receive(PotRoomMessage.class)
|
||||
.onMessage(EnterPot.class, x -> onGetPotSession(chatRoom, x))
|
||||
.build();
|
||||
}
|
||||
|
||||
public static Behavior<PotRoomMessage> create(int numberOfParticipants, int totalTurns) {
|
||||
return Behaviors.setup(
|
||||
ctx -> new PotRoom(ctx, numberOfParticipants, totalTurns)
|
||||
.createPotBehaviour(ctx.getSelf()));
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package dev.freireservices.social_altruism.chat.potroom;
|
||||
|
||||
import akka.actor.typed.ActorRef;
|
||||
|
||||
import static dev.freireservices.social_altruism.chat.participant.ParticipantProtocol.ParticipantMessage;
|
||||
|
||||
public class PotRoomProtocol {
|
||||
public interface PotRoomMessage {}
|
||||
|
||||
public record EnterPot(ActorRef<ParticipantMessage> replyTo)
|
||||
implements PotRoomMessage {}
|
||||
}
|
@ -0,0 +1,129 @@
|
||||
package dev.freireservices.social_altruism.chat.potroom;
|
||||
|
||||
import akka.actor.typed.ActorRef;
|
||||
import akka.actor.typed.Behavior;
|
||||
import akka.actor.typed.javadsl.ActorContext;
|
||||
import akka.actor.typed.javadsl.Behaviors;
|
||||
import dev.freireservices.social_altruism.chat.participant.ParticipantProtocol.ParticipantMessage;
|
||||
import dev.freireservices.social_altruism.chat.participant.ParticipantProtocol.PotReturned;
|
||||
import dev.freireservices.social_altruism.chat.participant.ParticipantProtocol.SessionEnded;
|
||||
import dev.freireservices.social_altruism.chat.participant.ParticipantProtocol.SessionStarted;
|
||||
import dev.freireservices.social_altruism.chat.potroom.PotRoomProtocol.PotRoomMessage;
|
||||
import dev.freireservices.social_altruism.chat.potroom.SessionProtocol.*;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
public class Session {
|
||||
|
||||
private final ActorContext<SessionMessage> context;
|
||||
private int currentTurn = 0;
|
||||
private final int totalTurns;
|
||||
private final List<ActorRef<ParticipantMessage>> participants;
|
||||
|
||||
private double currentPot = 0.0;
|
||||
private int numberOfParticipantsInCurrentTurn;
|
||||
|
||||
|
||||
public Session(ActorContext<SessionMessage> context, List<ActorRef<ParticipantMessage>> participants, int totalTurns) {
|
||||
this.context = context;
|
||||
this.participants = participants;
|
||||
this.totalTurns = totalTurns;
|
||||
}
|
||||
|
||||
|
||||
public void resetPot() {
|
||||
this.currentPot = 0;
|
||||
}
|
||||
|
||||
public void addToPot(double pot) {
|
||||
currentPot += pot;
|
||||
}
|
||||
|
||||
public void incrementParticipantsInTurn() {
|
||||
this.numberOfParticipantsInCurrentTurn++;
|
||||
}
|
||||
|
||||
public void resetNumberOfParticipantsInTurn() {
|
||||
this.numberOfParticipantsInCurrentTurn = 0;
|
||||
}
|
||||
|
||||
public int incrementCurrentTurnAndGet() {
|
||||
return ++this.currentTurn;
|
||||
}
|
||||
|
||||
|
||||
public Behavior<SessionMessage> createSessionBehaviour() {
|
||||
return Behaviors.receive(SessionMessage.class)
|
||||
.onMessage(StartSession.class, startSession -> onSessionStarted(startSession.chatRoom()
|
||||
, startSession.replyTo(), startSession.participants(), totalTurns))
|
||||
.onMessage(PlayTurn.class, this::onPlayTurn)
|
||||
.onMessage(EndSession.class, endSession -> onSessionEnded(participants))
|
||||
.onMessage(ShareReturnPotWithParticipants.class,
|
||||
sharePot -> onReturnPotToParticipants(sharePot.session(), sharePot.participants(), sharePot.returnedAmount()))
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
public static Behavior<SessionMessage> create(List<ActorRef<ParticipantMessage>> participants, int totalTurns) {
|
||||
return Behaviors.setup(context -> new Session(context, participants, totalTurns)
|
||||
.createSessionBehaviour());
|
||||
}
|
||||
|
||||
|
||||
private Behavior<SessionMessage> onPlayTurn(
|
||||
PlayTurn playTurn) {
|
||||
context.getLog()
|
||||
.info("Participant {} joined for turn {} with {}",
|
||||
playTurn.replyTo().path().name(),
|
||||
playTurn.turn(),
|
||||
playTurn.pot());
|
||||
|
||||
// Add to current pot
|
||||
addToPot(playTurn.pot());
|
||||
incrementParticipantsInTurn();
|
||||
|
||||
if (getNumberOfParticipantsInCurrentTurn() == participants.size()) {
|
||||
|
||||
double amountToShare = (getCurrentPot() * 2) / participants.size();
|
||||
|
||||
playTurn.session().narrow().tell(new ShareReturnPotWithParticipants(playTurn.session(), playTurn.participants(), amountToShare));
|
||||
|
||||
resetPot();
|
||||
resetNumberOfParticipantsInTurn();
|
||||
|
||||
context.getLog().info("Turn {} complete", getCurrentTurn());
|
||||
|
||||
if (incrementCurrentTurnAndGet() == totalTurns) {
|
||||
context.getLog().info("All turns completed - Waiting for other messages, then ending session.");
|
||||
context.scheduleOnce(Duration.ofSeconds(3), playTurn.session().narrow(), new EndSession());
|
||||
}
|
||||
}
|
||||
return Behaviors.same();
|
||||
}
|
||||
|
||||
private Behavior<SessionMessage> onSessionEnded(List<ActorRef<ParticipantMessage>> participants) {
|
||||
participants.forEach(participant -> participant.tell(new SessionEnded()));
|
||||
return Behaviors.stopped();
|
||||
}
|
||||
|
||||
private static Behavior<SessionMessage> onSessionStarted(
|
||||
ActorRef<PotRoomMessage> chatRoom,
|
||||
ActorRef<SessionMessage> session,
|
||||
List<ActorRef<ParticipantMessage>> participants,
|
||||
int totalTurns) {
|
||||
participants.forEach(s -> s.tell(new SessionStarted(chatRoom, session, participants, totalTurns)));
|
||||
return Behaviors.same();
|
||||
}
|
||||
|
||||
private static Behavior<SessionMessage> onReturnPotToParticipants(
|
||||
ActorRef<SessionMessage> session,
|
||||
List<ActorRef<ParticipantMessage>> participants,
|
||||
double returnedAmount) {
|
||||
participants.forEach(participant -> participant.tell(new PotReturned(session, participant, returnedAmount)));
|
||||
return Behaviors.same();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package dev.freireservices.social_altruism.chat.potroom;
|
||||
|
||||
import akka.actor.typed.ActorRef;
|
||||
import dev.freireservices.social_altruism.chat.participant.ParticipantProtocol.ParticipantMessage;
|
||||
import dev.freireservices.social_altruism.chat.potroom.PotRoomProtocol.PotRoomMessage;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
public class SessionProtocol {
|
||||
|
||||
public interface SessionMessage {
|
||||
}
|
||||
|
||||
public record StartSession(
|
||||
ActorRef<PotRoomMessage> chatRoom,
|
||||
ActorRef<SessionMessage> replyTo,
|
||||
List<ActorRef<ParticipantMessage>> participants)
|
||||
implements SessionMessage {
|
||||
}
|
||||
|
||||
|
||||
public record PlayTurn(
|
||||
ActorRef<SessionMessage> session,
|
||||
ActorRef<ParticipantMessage> replyTo,
|
||||
List<ActorRef<ParticipantMessage>> participants,
|
||||
int turn,
|
||||
double pot)
|
||||
implements SessionMessage {
|
||||
}
|
||||
|
||||
public record ShareReturnPotWithParticipants(
|
||||
ActorRef<SessionMessage> session,
|
||||
List<ActorRef<ParticipantMessage>> participants,
|
||||
double returnedAmount) implements SessionMessage {
|
||||
}
|
||||
|
||||
|
||||
public record EndSession() implements SessionMessage { }
|
||||
|
||||
}
|
18
src/main/resources/log4j.xml
Normal file
18
src/main/resources/log4j.xml
Normal file
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
|
||||
<log4j:configuration debug="true"
|
||||
xmlns:log4j='http://jakarta.apache.org/log4j/'>
|
||||
|
||||
<appender name="console" class="org.apache.log4j.ConsoleAppender">
|
||||
<layout class="org.apache.log4j.PatternLayout">
|
||||
<param name="ConversionPattern"
|
||||
value="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n" />
|
||||
</layout>
|
||||
</appender>
|
||||
|
||||
<root>
|
||||
<level value="DEBUG" />
|
||||
<appender-ref ref="console" />
|
||||
</root>
|
||||
|
||||
</log4j:configuration>
|
@ -0,0 +1,57 @@
|
||||
package dev.freireservices.social_altruism.chat;
|
||||
|
||||
import akka.actor.testkit.typed.javadsl.ActorTestKit;
|
||||
import akka.actor.typed.ActorRef;
|
||||
import dev.freireservices.social_altruism.chat.participant.Participant;
|
||||
import dev.freireservices.social_altruism.chat.participant.ParticipantProtocol.ParticipantMessage;
|
||||
import dev.freireservices.social_altruism.chat.potroom.PotRoom;
|
||||
import dev.freireservices.social_altruism.chat.potroom.PotRoomProtocol;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static dev.freireservices.social_altruism.chat.participant.ParticipantType.*;
|
||||
|
||||
public class CaseStudiesTests {
|
||||
public static final int INITIAL_COINS = 100;
|
||||
public static final int TOTAL_PARTICIPANTS = 3;
|
||||
public static final int TOTAL_TURNS = 100;
|
||||
|
||||
final static ActorTestKit testKit = ActorTestKit.create();
|
||||
|
||||
@Test
|
||||
public void testCooperation() {
|
||||
|
||||
var potRoom = PotRoom.create(TOTAL_PARTICIPANTS, TOTAL_TURNS);
|
||||
|
||||
ActorRef<PotRoomProtocol.PotRoomMessage> chatRoomTest =
|
||||
testKit.spawn(potRoom, "potRoom");
|
||||
|
||||
ActorRef<ParticipantMessage> p1 =
|
||||
testKit.spawn(Participant.create(INITIAL_COINS, PICARO), "PICARO-1");
|
||||
|
||||
ActorRef<ParticipantMessage> p2 =
|
||||
testKit.spawn(Participant.create(INITIAL_COINS, JUSTICIERO), "JUSTICIERO-1");
|
||||
|
||||
ActorRef<ParticipantMessage> p3 =
|
||||
testKit.spawn(Participant.create(INITIAL_COINS, SANTO), "SANTO-1");
|
||||
|
||||
// Enter POT
|
||||
chatRoomTest.tell(new PotRoomProtocol.EnterPot(p1));
|
||||
chatRoomTest.tell(new PotRoomProtocol.EnterPot(p2));
|
||||
chatRoomTest.tell(new PotRoomProtocol.EnterPot(p3));
|
||||
|
||||
try {
|
||||
TimeUnit.MINUTES.sleep(1);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void cleanup() {
|
||||
testKit.shutdownTestKit();
|
||||
}
|
||||
}
|
@ -0,0 +1,108 @@
|
||||
package dev.freireservices.social_altruism.chat;
|
||||
|
||||
import akka.actor.testkit.typed.javadsl.ActorTestKit;
|
||||
import akka.actor.testkit.typed.javadsl.BehaviorTestKit;
|
||||
import akka.actor.testkit.typed.javadsl.TestProbe;
|
||||
import akka.actor.typed.ActorRef;
|
||||
import dev.freireservices.social_altruism.chat.participant.Participant;
|
||||
import dev.freireservices.social_altruism.chat.participant.ParticipantProtocol;
|
||||
import dev.freireservices.social_altruism.chat.participant.ParticipantProtocol.ParticipantMessage;
|
||||
import dev.freireservices.social_altruism.chat.potroom.PotRoom;
|
||||
import dev.freireservices.social_altruism.chat.potroom.PotRoomProtocol;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import static dev.freireservices.social_altruism.chat.participant.ParticipantType.*;
|
||||
|
||||
public class ProtocolTests {
|
||||
public static final int INITIAL_COINS = 100;
|
||||
public static final int TOTAL_PARTICIPANTS = 4;
|
||||
|
||||
@Test
|
||||
public void testSessionStartedOnJoinParticipants() {
|
||||
|
||||
final ActorTestKit testKit = ActorTestKit.create();
|
||||
|
||||
TestProbe<ParticipantMessage> testProbe =
|
||||
testKit.createTestProbe("TestProbe", ParticipantMessage.class);
|
||||
|
||||
var potRoom = PotRoom.create(TOTAL_PARTICIPANTS, 1);
|
||||
ActorRef<PotRoomProtocol.PotRoomMessage> chatRoomTest =
|
||||
testKit.spawn(potRoom, "potRoom");
|
||||
|
||||
BehaviorTestKit<PotRoomProtocol.PotRoomMessage> test = BehaviorTestKit.create(potRoom);
|
||||
|
||||
ActorRef<ParticipantMessage> p1 =
|
||||
testKit.spawn(Participant.create(INITIAL_COINS, PICARO), "PICARO-1");
|
||||
|
||||
ActorRef<ParticipantMessage> p2 =
|
||||
testKit.spawn(Participant.create(INITIAL_COINS, JUSTICIERO), "JUSTICIERO-1");
|
||||
|
||||
ActorRef<ParticipantMessage> p3 =
|
||||
testKit.spawn(Participant.create(INITIAL_COINS, SANTO), "SANTO-1");
|
||||
|
||||
// Enter POT
|
||||
chatRoomTest.tell(new PotRoomProtocol.EnterPot(p1));
|
||||
chatRoomTest.tell(new PotRoomProtocol.EnterPot(p2));
|
||||
chatRoomTest.tell(new PotRoomProtocol.EnterPot(p3));
|
||||
chatRoomTest.tell(new PotRoomProtocol.EnterPot(testProbe.ref()));
|
||||
|
||||
//Session started
|
||||
|
||||
testProbe.expectMessageClass(ParticipantProtocol.SessionGranted.class, Duration.ofSeconds(20));
|
||||
testProbe.expectMessageClass(ParticipantProtocol.SessionStarted.class, Duration.ofSeconds(20));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testActorGetsSessionGranted() {
|
||||
final ActorTestKit testKit = ActorTestKit.create();
|
||||
TestProbe<ParticipantMessage> testProbe =
|
||||
testKit.createTestProbe("TestProbe");
|
||||
|
||||
ActorRef<PotRoomProtocol.PotRoomMessage> chatRoomTest =
|
||||
testKit.spawn(PotRoom.create(1, 1), "chatRoom");
|
||||
|
||||
chatRoomTest.tell(new PotRoomProtocol.EnterPot(testProbe.ref()));
|
||||
|
||||
testProbe.expectMessageClass(ParticipantProtocol.SessionGranted.class, Duration.ofSeconds(10));
|
||||
|
||||
// #assert
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testActorGetsSessionDenied() {
|
||||
final ActorTestKit testKit = ActorTestKit.create();
|
||||
TestProbe<ParticipantMessage> testProbe =
|
||||
testKit.createTestProbe("TestProbe");
|
||||
|
||||
ActorRef<PotRoomProtocol.PotRoomMessage> chatRoomTest =
|
||||
testKit.spawn(PotRoom.create(2, 1), "chatRoom");
|
||||
|
||||
chatRoomTest.tell(new PotRoomProtocol.EnterPot(testProbe.ref()));
|
||||
chatRoomTest.tell(new PotRoomProtocol.EnterPot(testProbe.ref()));
|
||||
|
||||
testProbe.expectMessageClass(ParticipantProtocol.SessionDenied.class, Duration.ofSeconds(5));
|
||||
|
||||
// #assert
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultipleSessions() {
|
||||
final ActorTestKit testKit = ActorTestKit.create();
|
||||
TestProbe<ParticipantMessage> testProbe =
|
||||
testKit.createTestProbe("TestProbe");
|
||||
|
||||
ActorRef<PotRoomProtocol.PotRoomMessage> chatRoomTest =
|
||||
testKit.spawn(PotRoom.create(2, 1), "chatRoom");
|
||||
|
||||
chatRoomTest.tell(new PotRoomProtocol.EnterPot(testProbe.ref()));
|
||||
chatRoomTest.tell(new PotRoomProtocol.EnterPot(testProbe.ref()));
|
||||
|
||||
testProbe.expectMessageClass(ParticipantProtocol.SessionDenied.class, Duration.ofSeconds(5));
|
||||
|
||||
// #assert
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user