聯系方式

您當前位置:首頁 >> Java編程Java編程

日期:2019-06-12 10:36

School of Information Technology and Mathematical Sciences

INFT 3030 Concurrent Programming

Concurrent Programming Assignment SP2 2019

Introduction

This document defines the requirements for the assignment in Concurrent Programming. The assignment is intended to give

you experience in modelling a concurrent requirement and writing a concurrent program in Java to implement it. The

application is a multi-player game server (MPGS).

A MPGS is software that runs on a computer connected to Internet. It enables and handles all communication between players

of games running on Internet connected devices so that they can participate in a shared game. A turn based game is often

played using a multiplayer game server. In these games each player (using client software) takes a turn in giving input to the

game server.

Google (PlayServices) and Apple (GameCenter) provide a MPGS for their mobile platforms. There are also independent

companies providing these services; examples of which are Photon (https://www.exitgames.com/en/OnPremise) and Smartfox

(http://www.smartfoxserver.com/products).

MPGS can quickly become very complex and contain many functions that we won’t be implementing in this assignment. The

scope of the MPGS to be implemented by you and your team in for the Concurrency Programming assignment are the ability

for players to connect and to play a game together, noting the following:

Only players who are registered are allowed to connect to and play on the MPGS. It is acceptable to have a list of

registered players in an external database, i.e. you can assume that the registration is taken care of by a separate piece

of software and the list of registered players is provided by that software. Typically, when a player connects to the

MPGS, they are often placed into a “lobby”.

Normally a player in the lobby would then choose a game to join or start their own and hope others will join. However

in this assignment, you are only required to have one multiplayer game to join and everyone who is logged in will have

to play in that one game.

The game to be hosted by the MPGS will be called multiplayer snakes

Multiplayer snakes

Single player versions of snakes can be found in many places on the internet, e.g. http://playsnake.org

and http://codeincomplete.com/projects/snakes/. The rules vary between different variants:

you can get points for eating fruit, as well as simply surviving as long as you can

it can be OK to cross the edge of the screen, or this can end your game

game time can be limited so you get a fixed time to score, or the game can go on until you cross the edge of the screen

or collide with yourself or another player.

A downloadable multiplayer version of snakes for windows is here: http://sandbox.yoyogames.com/games/172375/download. In

this case there are no food items you just try to block other snakes and need to be the last snake left with somewhere to move

to win. Another example of the idea can be viewed at https://www.youtube.com/watch?v=hRy_qQLdptA although you may not

understand the German commentary!

For the purposes of this assignment, you are free to choose your own rules for the actual snakes game. The main focus for this

assessment is the way your MPGS supports multiple concurrent players.

2

Server design

After they have connected and joined a game, players send to the game server their moves. These moves are very simple: Up,

Down, Left, Right or No Move. A No Move could mean either keep going in the same direction as the last move or stop and

wait. The game server takes all the moves from all the players and updates its copy of the game board. If you chose to have

fruit the snakes eat to get points, the server will need to detect if fruit has been eaten and updates player scores. The server

then broadcasts the game board (with all the other players shown and any fruit left or added) to each player so they can make

the next move.

In a fully networked implementation of this game each player will have to display on their screen the current state of play and

then transmit moves to the server (using TCP/IP or UDP sockets) over the internet. Given this can be a time intensive exercise,

in this assignment, we are going to limit the implementation to save on programming time and leave time to concentrate on

the concurrent aspects of the server and players. For the MPGS you will implement, no networking is required. In keeping with

the rest of this course we will restrict the game server and players to be threads all on the same Java process (JVM).

This means that you will not have to write TCP/IP or UDP socket code, rather you will need to manage the communication

between players and the server using Java constructs. This also means that initially at least you can get the server to draw the

game state on a single screen where all the players can see it rather than sending a copy down to each player for them to draw

on their own screen.

Modelling

In addition to writing concurrent Java code for the game server and clients (players), you will need to construct a model of their

game server and players using the LTSA tool. The modelling will need to accurately capture the concurrent behaviour of your

proposed server and show that it is both safe, i.e. it is not likely to freeze. And that it is in fact using multiple threads to perform

its functions in a way than can be scaled up to many different players.

Testing

You will be required to demonstrate testing to show that the game can be played by 4 real players and up to 100 simulated

players. Simulated players just make random moves on the board. It would be expected that you apply testing concepts that

have been discussed in the lectures (JUnit assertions and mock objects).

Assessment summary

For internal students this will be a group project with teams of 4. External students will work alone on the assignment and

hence will not need to provide an as complete a solution as internal students.

The assessment scoring is divided into two stages.

Checkpoint 1 Checkpoint 2

Final Submission and

Presentation Total

Internal 2.5 points scored as a group 2.5 points scored as a group 10 points scored individually

5 points scored as a group 20

External 2.5 2.5 15 20

The following subsections provide details that are focused on internal students. Clarifications for external students are provided

at the end of each section.

Checkpoint 1

This body of work is to be presented in the week 6 lab slot.

The purpose of the check point provides an opportunity for the design of the server to be checked before implementation

commences. At this checkpoint the group should have finalised the concurrency design of the server and player roles and

created a Java class design document. The group should also have a draft LTSA model of their concurrency design. All this is to

be gathered in a design report of approximately 3000 words (or equivalent with diagrams). The report needs to allocate Java

classes to group members for the first sprint to implementation.

External students will do this as individuals. The deliverable is the same, but they do not need to prepare such a large document

(1000 words).

3

Checkpoint 2

This body of work is to be presented in the week 8 lab slot.

The purpose of this checkpoint is to evaluate some early working code as planned for the first sprint in checkpoint 1. There

should be an emphasis on a thread-safe monitor controlled buffer between clients and the server and some initial

implementation of the threaded server code especially the thread safe game state code. The LTSA model should be nearing

completion. Some attention should be focused on testing and how this will be performed. Finally plans for the final

implementation should be finalized and every team member should have some coding allocated to complete the assignment.

An updated report will be required for this checkpoint and working code is required.

External students do not need as large an updated report (1000 words) and the scope of code implementation will be reduced.

Final Submission and Presentation

The final submission will provide working code which allows four players to engage in the game and code to allow simulated

play for up to 100 players. There will also be a completed LTSA model of the concurrent behaviour the players and the game

server. The model should demonstrate that the game server is capable of concurrent operation and that it has no potential

freezes (deadlocks). A report will describe the structure of the code for both the model and the actual implementation. The

report should be approximately 5000 words or equivalent diagrams. The group will present the server working with 4 real

players and 100 simulated players. The group mark will be allocated for successful integration of group member’s code and

model and the demonstration/presentation. The individual marks will be allocated to the code each student has written and

their individual contribution to contribution to the model and the report.

External students need only demonstrate one real player, and scaling up to 4 simulated players. External students need only

provide a report of 1000 words. External students can demonstrate via a screen capture or video.

4

Technical Specifications

Stage 1

The first stage of the project should be to allow players to login.

Each player will be modelled and coded as a concurrent thread. The server design should be able to handle concurrent login

requests from different players.

Logins must be thread-safe on the server. It is not necessary to support registration. Registering players can be handled by

manually loading their usernames and passwords into a suitable database. A suggested package is MapDB (as presented in

Appendix 1) which is a good choice for a thread-safe embedded database.

It is a requirement for the concurrent login code that a thread-safe standard Java collection is NOT to be used to pass messages

between the player logging in and the server. It is also a requirement that monitors be used to manage access to this collection.

Stage 2

The second stage of the project is to implement the game playing part of the server.

Once the server starts it should be ready to accept logged in players playing the game.

It is a requirement to use thread safe collections for the communication channels between players and the server for game

playing and for the storage of the game state. It is a requirement to use a thread pool for game player interactions based on the

java.util.concurrent.executor model. The actual game playing will adopt the pure client server model.

The server's main loop would be a concurrent version of this pseudo code:

while not done

for each player in world

if input exists

get player command

execute player command

tell player of the results

simulate the world

broadcast to all players

The client's main loop would be like this:

while not done

if player has typed any text

send typed text to server

if output from server exists

print output

In the case of the assignment Java threaded version with no networking the server could take care of updating the screen since

all players can see the single screen.

There is a simple snake single player code example at: https://code.google.com/p/java-snake/source/browse/trunk/javasnake/src/snake/Main.java.

Code from here tested on IntelliJ 14 community edition can be found in Appendix 2

5

Appendix 1

Code for concurrent persistent hashmaps. See http://www.mapdb.org

You need to load the library for MapDB via Maven

IntelliJ: File->Project Structure->Libraries->+->Browse-> select org.mapdb.1.0.6

import org.mapdb.*;

import java.io.File;

import java.io.Serializable;

import java.util.HashMap;

import java.util.concurrent.ConcurrentNavigableMap;

public class Main {

public static void main(String[] args) {

// configure and open database using builder pattern.

// all options are available with code auto-completion.

DB db = DBMaker.newFileDB(new File("testdb"))

.closeOnJvmShutdown()

.encryptionEnable("password")

.make();

// open existing an collection (or create new)

ConcurrentNavigableMap<Integer, String> map = db.getTreeMap("collectionName");

// To simplfy access to the classes stored as an infostore use generics

ConcurrentNavigableMap<String, InfoStor> mymap = db.getTreeMap("myInfoStoreCollection");

// example of ConcurrentNavigableMap taken from

// http://examples.javacodegeeks.com/core-java/util/concurrent/concurrentnavigablemap/java-util-

// concurrent-concurrentnavigablemap-example/

ConcurrentNavigableMap<Integer, String> navmap = db.getTreeMap("myNavmap");

navmap.put(1, "Sunday");

navmap.put(2, "Monday");

navmap.put(3, "Tuesday");

navmap.put(4, "Wednesday");

navmap.put(5, "Thursday");

navmap.put(6, "Friday");

navmap.put(7, "Saturday");

System.out.println("1. descendingKeySet(): " + navmap.descendingKeySet() + "\n");

System.out.println("2. descendingMap(): " + navmap.descendingMap() + "\n");

System.out.println("3. headMap(K toKey): " + navmap.headMap(3) + "\n");

System.out.println("4. headMap(K toKey, boolean inclusive): " + navmap.headMap(3, true) + "\n");

System.out.println("5. keySet(): " + navmap.keySet() + "\n");

System.out.println("6. navigableKeySet(): " + navmap.navigableKeySet() + "\n");

System.out.println("7. subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive): "

+ navmap.subMap(3, true, 6, true) + "\n");

System.out.println("8. subMap(K fromKey, K toKey): " + navmap.subMap(3, 6) + "\n");

System.out.println("9. tailMap(K fromKey): " + navmap.tailMap(3) + "\n");

System.out.println("10. tailMap(K fromKey, boolean inclusive): " + navmap.tailMap(3, true) + "\n");

map.put(1, "one");

map.put(2, "two");

// map.keySet() is now [1,2]

System.out.println(map.get(2));

db.commit(); //persist changes into disk

map.put(3, "three");

// map.keySet() is now [1,2,3]

db.rollback(); //revert recent changes

// map.keySet() is now [1,2]

// This was taken from

// http://stackoverflow.com/questions/12099843/storing-a-new-object-as-the-value-of-a-hashmap

HashMap<String, InfoStor> mapper = new HashMap<String, InfoStor>();

//HashMap<String, Object> mapper = new HashMap();

//InfoStor myInfoStore = new InfoStor("NS02");

System.out.println("Trying");

mymap.put("NS02", new InfoStor("NS02"));

System.out.println(mymap.get("NS02").getName());

db.close();

}

}

6

// this class must be serializable

class InfoStor implements Serializable {

private String vmName;

private String platform;

private Integer memory;

public InfoStor (String name) {

vmName = name;

}

String getName(){

return vmName;

}

void setPlatform(String p){

platform = p;

}

String getPlatform(){

return platform;

}

void setMemory(Integer m){

memory = m;

}

Integer getMemory(){

return memory;

}

}

7

Appendix 2

Simple snake code from https://code.google.com/p/java-snake/source/browse/trunk/java-snake/src/snake/Main.java

package snake;

import java.awt.Canvas;

import java.awt.Color;

import java.awt.Dimension;

import java.awt.Font;

import java.awt.Frame;

import java.awt.Graphics;

import java.awt.Toolkit;

import java.awt.event.KeyEvent;

import java.awt.event.KeyListener;

import java.awt.event.WindowEvent;

import java.awt.event.WindowListener;

import java.awt.image.BufferStrategy;

import java.util.logging.Level;

import java.util.logging.Logger;

/**

* @author Peuch

*/

public class Main implements KeyListener, WindowListener {

// KEYS MAP

public final static int UP = 0;

public final static int DOWN = 1;

public final static int LEFT = 2;

public final static int RIGHT = 3;


// GRID CONTENT

public final static int EMPTY = 0;

public final static int FOOD_BONUS = 1;

public final static int FOOD_MALUS = 2;

public final static int BIG_FOOD_BONUS = 3;

public final static int SNAKE = 4;

private int[][] grid = null;

private int[][] snake = null;

private int direction = -1;

private int next_direction = -1;

private int height = 600;

private int width = 600;

private int gameSize = 40;

private long speed = 70;

private Frame frame = null;

private Canvas canvas = null;

private Graphics graph = null;

private BufferStrategy strategy = null;

private boolean game_over = false;

private boolean paused = false;


private int score = 0;

private int grow = 0;


private int seconde,minute,milliseconde = 0; // Clock values

private long cycleTime = 0;

private long sleepTime = 0;

private int bonusTime = 0;

private int malusTime = 0;

/**

* @param args

* the command line arguments

*/

public static void main(String[] args) {

Main game = new Main();

game.init();

game.mainLoop();

}

public Main() {

super();

frame = new Frame();

canvas = new Canvas();

grid = new int[gameSize][gameSize];

snake = new int[gameSize * gameSize][2];

}

public void init() {

8

frame.setSize(width + 7, height + 27);

frame.setResizable(false);

frame.setLocationByPlatform(true);

canvas.setSize(width + 7, height + 27);

frame.add(canvas);

canvas.addKeyListener(this);

frame.addWindowListener(this);

frame.dispose();

frame.validate();

frame.setTitle("Snake");

frame.setVisible(true);

canvas.setIgnoreRepaint(true);

canvas.setBackground(Color.WHITE);


canvas.createBufferStrategy(2);


strategy = canvas.getBufferStrategy();

graph = strategy.getDrawGraphics();

initGame();

renderGame();

}

public void mainLoop() {

while (!game_over) {

cycleTime = System.currentTimeMillis();

if(!paused)

{

direction = next_direction;

moveSnake();

}

renderGame();

cycleTime = System.currentTimeMillis() - cycleTime;

sleepTime = speed - cycleTime;

if (sleepTime < 0)

sleepTime = 0;

try {

Thread.sleep(sleepTime);

} catch (InterruptedException ex) {

Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null,

ex);

}

}

}

private void initGame() {

// Initialise tabs

for (int i = 0; i < gameSize; i++) {

for (int j = 0; j < gameSize; j++) {

grid[i][j] = EMPTY;

}

}

for (int i = 0; i < gameSize * gameSize; i++) {

snake[i][0] = -1;

snake[i][1] = -1;

}

snake[0][0] = gameSize/2;

snake[0][1] = gameSize/2;

grid[gameSize/2][gameSize/2] = SNAKE;

placeBonus(FOOD_BONUS);

}

private void renderGame() {

int gridUnit = height / gameSize;

canvas.paint(graph);

do {

do {

graph = strategy.getDrawGraphics();

// Draw Background

graph.setColor(Color.WHITE);

graph.fillRect(0, 0, width, height);

// Draw snake, bonus ...

int gridCase = EMPTY;

for (int i = 0; i < gameSize; i++) {

9

for (int j = 0; j < gameSize; j++) {

gridCase = grid[i][j];

switch (gridCase) {

case SNAKE:

graph.setColor(Color.BLUE);

graph.fillOval(i * gridUnit, j * gridUnit,

gridUnit, gridUnit);

break;


case FOOD_BONUS:

graph.setColor(Color.darkGray);

graph.fillOval(i * gridUnit + gridUnit / 4, j

* gridUnit + gridUnit / 4, gridUnit / 2,

gridUnit / 2);

break;

case FOOD_MALUS:

graph.setColor(Color.RED);

graph.fillOval(i * gridUnit + gridUnit / 4, j

* gridUnit + gridUnit / 4, gridUnit / 2,

gridUnit / 2);

break;

case BIG_FOOD_BONUS:

graph.setColor(Color.GREEN);

graph.fillOval(i * gridUnit + gridUnit / 4, j

* gridUnit + gridUnit / 4, gridUnit / 2,

gridUnit / 2);

break;

default:

break;

}

}

}

graph.setFont(new Font(Font.SANS_SERIF, Font.BOLD, height / 40));

if (game_over) {

graph.setColor(Color.RED);

graph.drawString("GAME OVER", height / 2 - 30, height / 2);

graph.drawString("YOUR SCORE : " + score, height / 2 - 40, height / 2 +50);

graph.drawString("YOUR TIME : " + getTime(), height / 2 - 42, height / 2 +100);

}

else if (paused) {

graph.setColor(Color.RED);

graph.drawString("PAUSED", height / 2 - 30, height / 2);

}

graph.setColor(Color.BLACK);

graph.drawString("SCORE = " + score, 10, 20);

graph.drawString("TIME = " + getTime(), 100, 20); //Clock

graph.dispose();

} while (strategy.contentsRestored());

// Draw image from buffer

strategy.show();

Toolkit.getDefaultToolkit().sync();

} while (strategy.contentsLost());

}

private String getTime() {

String temps = new String(minute + ":" + seconde);

if (direction<0 || paused)

return temps;


milliseconde++;

if (milliseconde==14){

seconde++;

milliseconde=0;}

if (seconde==60){

seconde=0;

minute++;

}


return temps;

}


private void moveSnake() {

if (direction < 0) {

return;

}

int ymove = 0;

int xmove = 0;

10

switch (direction) {

case UP:

xmove = 0;

ymove = -1;

break;

case DOWN:

xmove = 0;

ymove = 1;

break;

case RIGHT:

xmove = 1;

ymove = 0;

break;

case LEFT:

xmove = -1;

ymove = 0;

break;

default:

xmove = 0;

ymove = 0;

break;

}

int tempx = snake[0][0];

int tempy = snake[0][1];

int fut_x = snake[0][0] + xmove;

int fut_y = snake[0][1] + ymove;


if(fut_x < 0)

fut_x = gameSize - 1;

if(fut_y < 0)

fut_y = gameSize - 1;

if(fut_x >= gameSize)

fut_x = 0;

if(fut_y >= gameSize)

fut_y = 0;


if (grid[fut_x][fut_y] == FOOD_BONUS)

{

grow++;

score++;

placeBonus(FOOD_BONUS);


}

if (grid[fut_x][fut_y] == FOOD_MALUS)

{

grow += 2;

score--;

}

else if(grid[fut_x][fut_y] == BIG_FOOD_BONUS)

{

grow += 3;

score +=3;

}

snake[0][0] = fut_x;

snake[0][1] = fut_y;

if ((grid[snake[0][0]][snake[0][1]] == SNAKE)) {

gameOver();

return;

}

grid[tempx][tempy] = EMPTY;

int snakex, snakey, i;

for (i = 1; i < gameSize * gameSize; i++) {

if ((snake[i][0] < 0) || (snake[i][1] < 0)) {

break;

}

grid[snake[i][0]][snake[i][1]] = EMPTY;

snakex = snake[i][0];

snakey = snake[i][1];

snake[i][0] = tempx;

snake[i][1] = tempy;

tempx = snakex;

tempy = snakey;

}

for (i = 0; i < gameSize * gameSize; i++) {

if ((snake[i][0] < 0) || (snake[i][1] < 0)) {

break;

11

}

grid[snake[i][0]][snake[i][1]] = SNAKE;

}

bonusTime--;

if (bonusTime == 0)

{

for (i = 0; i < gameSize; i++)

{

for (int j = 0; j < gameSize; j++)

{

if(grid[i][j]==BIG_FOOD_BONUS)

grid[i][j]=EMPTY;

}

}

}

malusTime --;

if (malusTime == 0)

{

for (i = 0; i < gameSize; i++)

{

for (int j = 0; j < gameSize; j++)

{

if(grid[i][j]==FOOD_MALUS)

grid[i][j]=EMPTY;

}

}

}

if (grow > 0) {

snake[i][0] = tempx;

snake[i][1] = tempy;

grid[snake[i][0]][snake[i][1]] = SNAKE;

if(score%10 == 0)

{

placeBonus(BIG_FOOD_BONUS);

bonusTime = 100;

}

if(score%5 == 0)

{

placeMalus(FOOD_MALUS);

malusTime = 100;

}

grow --;

}

}

private void placeBonus(int bonus_type) {

int x = (int) (Math.random() * 1000) % gameSize;

int y = (int) (Math.random() * 1000) % gameSize;

if (grid[x][y] == EMPTY) {

grid[x][y] = bonus_type;

} else {

placeBonus(bonus_type);

}

}


private void placeMalus(int malus_type) {

int x = (int) (Math.random() * 1000) % gameSize;

int y = (int) (Math.random() * 1000) % gameSize;

if (grid[x][y] == EMPTY) {

grid[x][y] = malus_type;

} else {

placeMalus(malus_type);

}

}

private void gameOver() {

game_over = true;

}

// IMPLEMENTED FUNCTIONS

public void keyPressed(KeyEvent ke) {

int code = ke.getKeyCode();

Dimension dim;

switch (code) {

case KeyEvent.VK_UP:

if (direction != DOWN) {

next_direction = UP;

}

break;

12

case KeyEvent.VK_DOWN:

if (direction != UP) {

next_direction = DOWN;

}

break;

case KeyEvent.VK_LEFT:

if (direction != RIGHT) {

next_direction = LEFT;

}

break;

case KeyEvent.VK_RIGHT:

if (direction != LEFT) {

next_direction = RIGHT;

}

break;

case KeyEvent.VK_F11:

dim = Toolkit.getDefaultToolkit().getScreenSize();

if ((height != dim.height - 50) || (width != dim.height - 50)) {

height = dim.height - 50;

width = dim.height - 50;

} else {

height = 600;

width = 600;

}

frame.setSize(width + 7, height + 27);

canvas.setSize(width + 7, height + 27);

canvas.validate();

frame.validate();

break;

case KeyEvent.VK_ESCAPE:

System.exit(0);

break;


case KeyEvent.VK_SPACE:

if(!game_over)

paused = !paused;

break;

default:

// Unsupported key

break;

}

}

public void windowClosing(WindowEvent we) {

System.exit(0);

}

// UNNUSED IMPLEMENTED FUNCTIONS

public void keyTyped(KeyEvent ke) {}

public void keyReleased(KeyEvent ke) {}

public void windowOpened(WindowEvent we) {}

public void windowClosed(WindowEvent we) {}

public void windowIconified(WindowEvent we) {}

public void windowDeiconified(WindowEvent we) {}

public void windowActivated(WindowEvent we) {}

public void windowDeactivated(WindowEvent we) {}

}

13

Administrivia

Extensions

Extensions for assignments may be available under the following conditions:

permanent or temporary disability

compassionate grounds

In all cases documentary evidence (e.g. medical certificate, road accident report, obituary) must be provided.

Late penalties

Late assignments that do not have approved extensions will not be accepted.

Academic conduct

Deliberate academic misconduct such as plagiarism is subject to penalties.

You are advised to become familiar with the University's policy available at http://www.unisa.edu.au/policies/manual/.

In an individual assignment or the individual part of a group assignment the work you submit must be entirely your own: no part

of your submission must be anybody else’s work or work that you did together with another student or students.

All use of published material (eg the Web, or a book) must be fully referenced. If you copy text from another source, you must

place it in quotation marks and include a reference to the original source. If you make any use of ideas or information, including

diagrams, from another source, you must reference that source.

Programming code cannot be included in an assignment copied from the web unless it is separately declared at the front of the

assignment. Code obtained from the web will not contribute to your individual or group grade in the assignment. If we find

even one line of code in your assignment that has been copied from the web and not declared you may receive zero for the

whole assignment. We will also check this assignment against previously submitted assignments and if we find any identical

code or sentences you may also get a mark of zero. If you get a mark of zero you may also be reported for plagiarism which

could lead to further consequences which are outlined in University policy. Please read the material on this page if you are not

sure.

There will be questions asked during presentation about the assignments which you may be unable to answer if you do not do

the assignment yourself.

All use of outside assistance – e.g. essay farms on the Web or work written for you by a friend – is strictly forbidden and will

attract a minimum penalty of zero for the assignment and may risk your expulsion from the university.

All the requirements documents for this assignment (including this one) are copyright to the University of South Australia. You

are not authorized to reproduce these requirements documents in any form nor submit or post or transmit them to any web

site. In particular posting these requirements on a web site which is aimed to solicit other people to do the assignment for a fee

is a breach of copyright and could be referred to the law enforcement authorities.

To defend yourself in the case of any suspicion of academic misconduct, you are strongly urged to retain all evidence of how

you developed your assignment, such as rough work sheets, notes, drafts, copies of reference material, minutes of meetings

etc.

You are free to discuss the assignment with others, and to give and receive help, including references and general discussion of

the main arguments and conclusions, as long as your part of the program code and text of your part of a report is written only

by yourself.


版權所有:編程輔導網 2018 All Rights Reserved 聯系方式:QQ:99515681 電子信箱:[email protected]
免責聲明:本站部分內容從網絡整理而來,只供參考!如有版權問題可聯系本站刪除。

25选5一等奖多少钱